This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
I am in the process of evaluating several ORM tools for an upcoming project. LightSpeed is one of those. I followed the GettingStarted video to create just a simple test that reads 1000 records from a table, one at a time. The lsmodel file contains three tables, Account, Address, and Company. Both lines within the for loop throw the same error, 'Object reference not set to an instance of an object". using (UDB3UnitOfWork uow = Repository.Context.CreateUnitOfWork()){ for (i = 1; i <= 1000; i++) { //AccountUdb account = uow.AccountUdbs.Where(a => a.AccountId == i).First(); ID = uow.AccountUdbs.Where(a => a.AccountId == i).First().AccountId; } } App.config (and Web.config) contain this code: <configSections><section name="lightSpeedContexts" type="Mindscape.LightSpeed.Configuration.LightSpeedConfigurationSection, Mindscape.LightSpeed"/> </configSections> < connectionStrings><add name="Dev" connectionString="Data Source=AppDev00\TSSQL;Initial Catalog=UDB3;Integrated Security=True;MultipleActiveResultSets=True"/> </connectionStrings> < lightSpeedContexts><add name="default" connectionStringName="Dev" dataProvider="SqlServer2005" identityMethod="IdentityColumn" pluralizeTableNames="false" /> </lightSpeedContexts> |
|
|
I hit the Post button before I realized I didn't include my question. Any ideas on what I should do next? I don't get far stepping into the code. How do I turn on the logging? I will dig deeper on this question. |
|
|
I've broken the code into more simple steps. var records = uow.AccountUdbs.Where(a => a.AccountId == i); I am now getting the error "The field [AccountId] on type [AccountUdb] must be nullable as it represents a hierachical relation". AccountID is the primary key and CANNOT be null. |
|
|
The primary key in LightSpeed is always represented by the Id property, which is defined on the Entity<TId> base class. By default, LightSpeed expects the database primary key column to be Id as well. If the primary key in the database is stored in an AccountId column, that is fine -- you just need to set the Identity Column Name of the AccountUdb entity to AccountId. However the identity property in LightSpeed will still be called Id. The AccountId property is not the primary key but a foreign key from the AccountUdb type to itself (representing e.g. a parent account). That is, you have an association from AccountUdb to AccountUdb. LightSpeed requires such foreign key fields to be nullable because the "chain of parenthood" has to end somewhere -- if the FK was not nullable then you would end up with either an infinite chain of parents or a circular relationship. In the designer, you can make this happen by selecting the association arrow and setting its Is Nullable property to True. Alternatively, if the association is not what you want, just delete it. So if your query is intended to get the account whose primary key is 1, it should look like this: uow.AccountUdbs.Where(a => a.Id == 1) Your current query will get the accounts whose *parent account ID* is 1. Hope this makes sense -- if not then could you post your .lsmodel file and your database CREATE TABLE scripts and we will take a look for you. Regarding turning on logging, you can do this by setting the Logger property of the LightSpeedContext: context.Logger = new ConsoleLogger(); // or new TraceLogger() You can also do this in configuration via the loggerClass attribute. |
|
|
Ivan, thanks for your comments. I now have a better understand of how this is working. Please let me know if the following explanation is correct. There is no field named ID in my Account_UDB table. The primary key is AccountID. LightSpeed correctly identifies the primary key because I see this line of code: [Table("Account_UDB", IdColumnName="AccountID", IdentityMethod=IdentityMethod.IdentityColumn)] Because the primary key is identified as AccountID no field named ID is being generated. Also, because there is a field named AccountID, LightSpeed thinks this field references another record within the Account_UDB table and creates an association where none should really exist. So is there a way to tell LightSpeed that AccountID is not a reference to another record within the Account_UDB table? Thanks |
|
|
Yes, your explanation is essentially correct but I would like to add a couple of things. First, the reason that no field named Id is being generated is not because the PK is called AccountId, but because the Id field is already defined on the Entity<> base class. The PK column is always aliased to the property named Id in LightSpeed, regardless of its name in the database. And the designer never shows the Id field because it is implicit in being an Entity. Second, there has to be a bit more than an AccountId field/column for LightSpeed to think that the AccountId field references another record within the Account_UDB table. At runtime -- which is when you get your "must be nullable" error -- LightSpeed actually looks for a pair of fields: an EntityHolder<> and a XxxId. Having a field just called XxxId is not, by itself, enough; the EntityHolder<> must be there too. (If you are using the designer, both these fields are generated if there is an association.) At design time, LightSpeed only identifies an XxxId column as an association if it is a foreign key -- again merely being named XxxId is not enough. Hope this all makes sense! So, how do we tell LightSpeed that AccountId is not a reference to another AccountUdb? Well, actually, we don't need to do that -- what we need to do is get rid of the AccountId field altogether! The AccountId column is already handled by the Entity.Id field (by virtue of the IdColumnName), so the AccountId field is superfluous. So how do we get rid of the AccountId field? Assuming you are using the designer, the AccountId field could come from one of two places: 1. A property named AccountId on the AccountUdb entity. In this case, delete the property. 2. An association called Account from the AccountUdb entity to itself (I think this is more likely). In this case, delete the association. If you are not using the designer, delete the AccountId field (and wrapper property) and the EntityHolder<AccountUdb> field (and wrapper property). You will also need to delete the EntityCollection<AccountUdb> field and wrapper property if there is one. Once you have got rid of the AccountId property or Account association, you should be able to perform your query as: uow.AccountUdbs.Where(a => a.Id == 1) and LightSpeed will translate a.Id into a query on the AccountId column (by using the IdColumnName). Finally, how did LightSpeed get confused about AccountId in the first place? Assuming you created this entity by dragging a table from ServerExplorer, it sounds like either your AccountId column is both a PK and a foreign key, or LightSpeed is mistakenly "doubling up" the AccountId column, using it both to set the IdColumnName and to create the Account association or AccountId property. Would it be possible for you to provide us with a copy of your database CREATE TABLE script and to let us know which database you are using so we can try to replicate this problem? Thanks! Also, if you are using the Update From Source or Update Database commands to synchronise the model and the database after doing the deletion above, please double-check any updates that LightSpeed suggests, as it may try to recreate its initial error. Once again, hope this makes sense -- please follow up if it doesn't! |
|
|
Thanks Ivan. I dug into the Account table and sure enough found a foreign key from AccountID to AccountID. It shouldn't have been there, so I deleted it. Once I did that, my test flew! I am impressed with the speed of the product! Now I am off to write some more tests. |
|