Entity and Collection Irregularities

Posts   
 
    
deathwish
User
Posts: 56
Joined: 07-Nov-2006
# Posted on: 21-Feb-2007 11:53:25   

Hi,

I am using SQL 2005, LLBLGen Pro v2, VS 2005.

I have a Person, User and Employee table in my database. Person table is 1 to 1 with User and User is 1 to 1 with Employee.

I have made User a subtype of Person, and Employee a subtype of User.


protected void Page_Load(object sender, EventArgs e)
{
    UserEntity userEntity = new UserEntity();
    userEntity.FetchUsingPK(new Guid("7D2EFFFA-9F78-4030-85AC-9E14E735BA79"));
}

Generates the following is SQL:


exec sp_executesql N'SELECT [preLink].[dbo].[Person].[PersonId], [preLink].[dbo].[Person].[DateTimeCreated] AS [DateTimeCreated_PersonEntity], 
[preLink].[dbo].[Person].[PersonTypeId], [preLink].[dbo].[Person].[SpousePersonId], [preLink].[dbo].[Person].[FirstName], [preLink].[dbo].[Person].[MiddleName], 
[preLink].[dbo].[Person].[LastName], [preLink].[dbo].[Person].[Initials], [preLink].[dbo].[Person].[Suffix], [preLink].[dbo].[Person].[FileAs], 
[preLink].[dbo].[Person].[IDNumber] AS [Idnumber], [preLink].[dbo].[Person].[DateOfBirth], [preLink].[dbo].[Person].[EthnicityId], [preLink].[dbo].[Person].[ReligionId], 
[preLink].[dbo].[Person].[CitizenshipId], [preLink].[dbo].[Person].[GenderId], [preLink].[dbo].[Person].[TitleId], [preLink].[dbo].[Person].[Image], 
[preLink].[dbo].[Person].[MaritalStatusId], [preLink].[dbo].[Person].[ReceiveDepartmentid], [preLink].[dbo].[User].[UserId], [preLink].[dbo].[User].[DateTimeCreated], 
[preLink].[dbo].[User].[ApplicationId], [preLink].[dbo].[User].[UserName], [preLink].[dbo].[User].[Password], [preLink].[dbo].[User].[LoweredUserName], 
[preLink].[dbo].[User].[MobileAlias], [preLink].[dbo].[User].[IsAnonymous], [preLink].[dbo].[User].[LastActivityDate], [preLink].[dbo].[User].[PasswordFormat], 
[preLink].[dbo].[User].[PasswordSalt], [preLink].[dbo].[User].[MobilePIN] AS [MobilePin], [preLink].[dbo].[User].[LoweredEmail], [preLink].[dbo].[User].[PasswordQuestion], 
[preLink].[dbo].[User].[PasswordAnswer], [preLink].[dbo].[User].[IsApproved], [preLink].[dbo].[User].[IsLockedOut], [preLink].[dbo].[User].[CreateDate], 
[preLink].[dbo].[User].[LastLoginDate], [preLink].[dbo].[User].[LastPasswordChangedDate], [preLink].[dbo].[User].[LastLockoutDate], 
[preLink].[dbo].[User].[FailedPasswordAttemptCount], [preLink].[dbo].[User].[FailedPasswordAttemptWindowStart], [preLink].[dbo].[User].[FailedPasswordAnswerAttemptCount], 
[preLink].[dbo].[User].[FailedPasswordAnswerAttemptWindowStart], [preLink].[dbo].[User].[Comment], [preLink].[dbo].[User].[DefaultSiteId] FROM ( [preLink].[dbo].[Person]  INNER 
JOIN [preLink].[dbo].[User]  ON  [preLink].[dbo].[Person].[PersonId]=[preLink].[dbo].[User].[UserId]) WHERE ( [preLink].[dbo].[Person].[PersonId] = @PersonId1)',N'@PersonId1 
uniqueidentifier',@PersonId1='7D2EFFFA-9F78-4030-85AC-9E14E735BA79'

Which is all fine. But when i do something like this:


protected void Page_Load(object sender, EventArgs e)
{
    UserCollection userCollection = new UserCollection();
    userCollection.GetMulti(UserFields.UserName == "plinky");
}

It generates:

[code] exec sp_executesql N'SELECT [preLink].[dbo].[Person].[PersonId] AS [F0], [preLink].[dbo].[Person].[DateTimeCreated] AS [F1], [preLink].[dbo].[Person].[PersonTypeId] AS [F2], [preLink].[dbo].[Person].[SpousePersonId] AS [F3], [preLink].[dbo].[Person].[FirstName] AS [F4], [preLink].[dbo].[Person].[MiddleName] AS [F5], [preLink].[dbo].[Person].[LastName] AS [F6], [preLink].[dbo].[Person].[Initials] AS [F7], [preLink].[dbo].[Person].[Suffix] AS [F8], [preLink].[dbo].[Person].[FileAs] AS [F9], [preLink].[dbo].[Person].[IDNumber] AS [F10], [preLink].[dbo].[Person].[DateOfBirth] AS [F11], [preLink].[dbo].[Person].[EthnicityId] AS [F12], [preLink].[dbo].[Person].[ReligionId] AS [F13], [preLink].[dbo].[Person].[CitizenshipId] AS [F14], [preLink].[dbo].[Person].[GenderId] AS [F15], [preLink].[dbo].[Person].[TitleId] AS [F16], [preLink].[dbo].[Person].[Image] AS [F17], [preLink].[dbo].[Person].[MaritalStatusId] AS [F18], [preLink].[dbo].[Person].[ReceiveDepartmentid] AS [F19], [preLink].[dbo].[User].[UserId] AS [F20], [preLink].[dbo].[User].[DateTimeCreated] AS [F21], [preLink].[dbo].[User].[ApplicationId] AS [F22], [preLink].[dbo].[User].[UserName] AS [F23], [preLink].[dbo].[User].[Password] AS [F24], [preLink].[dbo].[User].[LoweredUserName] AS [F25], [preLink].[dbo].[User].[MobileAlias] AS [F26], [preLink].[dbo].[User].[IsAnonymous] AS [F27], [preLink].[dbo].[User].[LastActivityDate] AS [F28], [preLink].[dbo].[User].[PasswordFormat] AS [F29], [preLink].[dbo].[User].[PasswordSalt] AS [F30], [preLink].[dbo].[User].[MobilePIN] AS [F31], [preLink].[dbo].[User].[LoweredEmail] AS [F32], [preLink].[dbo].[User].[PasswordQuestion] AS [F33], [preLink].[dbo].[User].[PasswordAnswer] AS [F34], [preLink].[dbo].[User].[IsApproved] AS [F35], [preLink].[dbo].[User].[IsLockedOut] AS [F36], [preLink].[dbo].[User].[CreateDate] AS [F37], [preLink].[dbo].[User].[LastLoginDate] AS [F38], [preLink].[dbo].[User].[LastPasswordChangedDate] AS [F39], [preLink].[dbo].[User].[LastLockoutDate] AS [F40], [preLink].[dbo].[User].[FailedPasswordAttemptCount] AS [F41], [preLink].[dbo].[User].[FailedPasswordAttemptWindowStart] AS [F42], [preLink].[dbo].[User].[FailedPasswordAnswerAttemptCount] AS [F43], [preLink].[dbo].[User].[FailedPasswordAnswerAttemptWindowStart] AS [F44], [preLink].[dbo].[User].[Comment] AS [F45], [preLink].[dbo].[User].[DefaultSiteId] AS [F46], [preLink].[dbo].[Employee].[EmployeeId] AS [F47], [preLink].[dbo].[Employee].[SupervisorEmployeeId] AS [F48], [preLink].[dbo].[Employee].[EmployeeNumber] AS [F49], [preLink].[dbo].[Employee].

 AS [F50], [preLink].[dbo].[Employee].[Position] AS [F51], [preLink].[dbo].[Employee].[VATRegistrationNumber] AS [F52], 
[preLink].[dbo].[Employee].[UIFNumber] AS [F53], [preLink].[dbo].[Employee].[BeneficiaryDetails] AS [F54], [preLink].[dbo].[Employee].[MedicalAlerts] AS [F55], 
[preLink].[dbo].[Employee].[ProvidentFundDetails] AS [F56] FROM (( [preLink].[dbo].[Person]  INNER JOIN [preLink].[dbo].[User]  ON  
[preLink].[dbo].[Person].[PersonId]=[preLink].[dbo].[User].[UserId]) LEFT JOIN [preLink].[dbo].[Employee]  ON  
[preLink].[dbo].[User].[UserId]=[preLink].[dbo].[Employee].[EmployeeId]) WHERE ( [preLink].[dbo].[User].[UserId] IS NOT NULL AND [preLink].[dbo].[User].[UserName] = 
@UserName1)',N'@UserName1 nvarchar(256)',@UserName1=N'plinky'

Why is the UserCollection query selecting employee information??

Thanks

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 21-Feb-2007 16:53:52   

That's because an Employee is a user at the end of the day (by inheritance rules).

What you need to do is, add a Type Filter, to the query to execlude the employees from the fetch.

filter.add(EmployeeEntity.GetEntityTypeFilter(true));

The true boolean is for negation. -> result means: Not of Employee Type (edit) you can find some explanation here: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=8890

deathwish
User
Posts: 56
Joined: 07-Nov-2006
# Posted on: 22-Feb-2007 08:40:35   

Hi Walaa,

Thanks very much i'll give it a bash.

deathwish
User
Posts: 56
Joined: 07-Nov-2006
# Posted on: 22-Feb-2007 11:26:51   

Hi Walaa,

After reading that thread and trying what you mentioned. It will return users that are not employees, which i do not want. I want all users but without their employee information.

So i guess i have to use something like what Otis posted in that thread:


EntityCollection<ItemBaseEntity> baseItems = new EntityCollection<ItemBaseEntity>(new ItemBaseEntityFactory());
IEntityFields2 fields = baseItems.EntityFactoryToUse.CreateFields();
List<IDataValueProjector> valueProjectors = new List<IDataValueProjectors>();
for(int i=0;i<fields.Count;i++)
{
    IEntityField2 field = fields[i];
    valueProjectors.Add(new DataValueProjector(field.Name, i, field.DataType));
}
DataProjectorToIEntityCollection2 projector = new DataProjectorToIEntityCollection2(baseItems);
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
    adapter.FetchProjection(valueProjectors, projector, fields, null, 0, true);
}

That is if you are using an adapter, which i am not. I am using the self servicing. So i tried:


TypedListDAO dao = new TypedListDAO();
PredicateExpression predicateExpression = new PredicateExpression();

UserCollection userCollection = new UserCollection(new UserEntityFactory());
IEntityFields fields = new UserEntityFactory().CreateFields();
List<IDataValueProjector> valueProjectors = new List<IDataValueProjector>();

for (int i = 0; i < fields.Count; i++)
{
    IEntityField field = fields[i];
    valueProjectors.Add(new DataValueProjector(field.Name, i, field.DataType));
}

DataProjectorToIEntityCollection projector = new DataProjectorToIEntityCollection(userCollection);

dao.GetAsProjection(valueProjectors, projector, null, fields, predicateExpression,  null, 0, false);

I see, via sql profiler, that it runs the correct query, the employee information is not selected, but it throws :


Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error: 


Line 67:            DataProjectorToIEntityCollection projector = new DataProjectorToIEntityCollection(userCollection);
Line 68: 
Line 69:            dao.GetAsProjection(valueProjectors, projector, null, fields, predicateExpression,  null, 0, false);



Any Ideas?

Thanks.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 22-Feb-2007 14:13:41   

Try to remove the factory from the collection constructor, as follows:

UserCollection userCollection = new UserCollection();

You may also try to use the Generic Form of the EntityCollection as in Frans's example.

deathwish
User
Posts: 56
Joined: 07-Nov-2006
# Posted on: 02-Mar-2007 13:06:32   

Hi,

Removed the factory and still returned the employee information.

I might be wrong, but can't u only use EntityCollection if you are using the Adapter and not the self servicing. The SelfServing collections do not inherit from the EntityCollection.

THis is a quote from the help file:

.NET 2.0, Selfservicing: All generated collection classes derive from EntityCollectionBase(of T), even if the entity type is a subtype. This is because C# and VB.NET don't support covariance: List(of String) isn't a subtype of List(of Object). This thus means that you can't cast a subtype's collection to a supertype's collection. We tried to have as much backwards compatibility as possible so the selfservicing collections aren't generic as in: EntityCollection(of T), but CustomerCollection, or OrderCollection, also because the generated collections have some entity type specific code in them. If ManagerEntity is a subtype of EmployeeEntity, and thus there's an EmployeeCollection, it can't be that ManagerCollection is a subtype of EmployeeCollection, because that would require EmployeeCollection(of T), which would break a lot of existing code.

Thanks.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 02-Mar-2007 18:37:36   

Could you also paste the stacktrace? The code looks OK, so I need a stacktrace to determine in which direction to look.

Frans Bouma | Lead developer LLBLGen Pro
deathwish
User
Posts: 56
Joined: 07-Nov-2006
# Posted on: 05-Mar-2007 15:05:06   

Hi, Sorry for the late post.

EDIT: Added SQL query:


exec sp_executesql N'SELECT [preLink].[dbo].[Person].[PersonId], [preLink].[dbo].[Person].[DateTimeCreated] AS [DateTimeCreated_PersonEntity], 
[preLink].[dbo].[Person].[PersonTypeId], [preLink].[dbo].[Person].[SpousePersonId], [preLink].[dbo].[Person].[FirstName], 
[preLink].[dbo].[Person].[MiddleName], [preLink].[dbo].[Person].[LastName], [preLink].[dbo].[Person].[Initials], 
[preLink].[dbo].[Person].[Suffix], [preLink].[dbo].[Person].[FileAs], [preLink].[dbo].[Person].[IDNumber] AS [Idnumber], 
[preLink].[dbo].[Person].[DateOfBirth], [preLink].[dbo].[Person].[EthnicityId], [preLink].[dbo].[Person].[ReligionId], 
[preLink].[dbo].[Person].[CitizenshipId], [preLink].[dbo].[Person].[GenderId], [preLink].[dbo].[Person].[TitleId], 
[preLink].[dbo].[Person].[Image], [preLink].[dbo].[Person].[MaritalStatusId], [preLink].[dbo].[Person].[ReceiveDepartmentid], 
[preLink].[dbo].[User].[UserId], [preLink].[dbo].[User].[DateTimeCreated], [preLink].[dbo].[User].[ApplicationId], 
[preLink].[dbo].[User].[UserName], [preLink].[dbo].[User].[Password], [preLink].[dbo].[User].[LoweredUserName], 
[preLink].[dbo].[User].[MobileAlias], [preLink].[dbo].[User].[IsAnonymous], [preLink].[dbo].[User].[LastActivityDate], 
[preLink].[dbo].[User].[PasswordFormat], [preLink].[dbo].[User].[PasswordSalt], [preLink].[dbo].[User].[MobilePIN] AS [MobilePin], 
[preLink].[dbo].[User].[LoweredEmail], [preLink].[dbo].[User].[PasswordQuestion], [preLink].[dbo].[User].[PasswordAnswer], 
[preLink].[dbo].[User].[IsApproved], [preLink].[dbo].[User].[IsLockedOut], [preLink].[dbo].[User].[CreateDate], 
[preLink].[dbo].[User].[LastLoginDate], [preLink].[dbo].[User].[LastPasswordChangedDate], [preLink].[dbo].[User].[LastLockoutDate], 
[preLink].[dbo].[User].[FailedPasswordAttemptCount], [preLink].[dbo].[User].[FailedPasswordAttemptWindowStart], 
[preLink].[dbo].[User].[FailedPasswordAnswerAttemptCount], [preLink].[dbo].[User].[FailedPasswordAnswerAttemptWindowStart], 
[preLink].[dbo].[User].[Comment], [preLink].[dbo].[User].[DefaultSiteId] FROM (( [preLink].[dbo].[Person]  INNER JOIN [preLink].[dbo].[User]  ON  
[preLink].[dbo].[Person].[PersonId]=[preLink].[dbo].[User].[UserId]) LEFT JOIN [preLink].[dbo].[Employee]  ON  
[preLink].[dbo].[User].[UserId]=[preLink].[dbo].[Employee].[EmployeeId]) WHERE ( ( [preLink].[dbo].[User].[UserName] = @UserName1))',N'@UserName1 
nvarchar(256)',@UserName1=N'ramrod'


Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error: 


Line 67:            DataProjectorToIEntityCollection projector = new DataProjectorToIEntityCollection(userCollection);
Line 68: 
Line 69:            dao.GetAsProjection(valueProjectors, projector, null, fields, predicateExpression, null, 0, false);
Line 70: 
Line 71: 


Source File: C:\Development\Prelink\prelink\src\preLink.Data\Security\SecurityHelper.cs Line: 69 

Stack Trace: 


[NullReferenceException: Object reference not set to an instance of an object.]
   SD.LLBLGen.Pro.ORMSupportClasses.ProjectionUtils.CreateHashValueFromValues(IList projectors, Object[] values) +248
   SD.LLBLGen.Pro.ORMSupportClasses.ProjectionUtils.FetchProjectionFromReader(List`1 valueProjectors, IGeneralDataProjector projector, IDataReader datasource, Int32 maxNumberOfItemsToReturn, Int32 pageNumber, Int32 pageSize, Boolean clientSideLimitation, Boolean clientSideDistinctFiltering, Boolean clientSidePaging) +464
   SD.LLBLGen.Pro.ORMSupportClasses.DaoBase.GetAsProjection(List`1 valueProjectors, IGeneralDataProjector projector, ITransaction transactionToUse, IRetrievalQuery queryToExecute) +182
   SD.LLBLGen.Pro.ORMSupportClasses.DaoBase.GetAsProjection(List`1 valueProjectors, IGeneralDataProjector projector, ITransaction transactionToUse, IEntityFields fields, IPredicateExpression filter, IRelationCollection relations, Int32 maxNumberOfItemsToReturn, ISortExpression sortClauses, IGroupByCollection groupByClause, Boolean allowDuplicates, Int32 pageNumber, Int32 pageSize) +110
   SD.LLBLGen.Pro.ORMSupportClasses.DaoBase.GetAsProjection(List`1 valueProjectors, IGeneralDataProjector projector, ITransaction transactionToUse, IEntityFields fields, IPredicateExpression filter, IRelationCollection relations, Int32 maxNumberOfItemsToReturn, Boolean allowDuplicates) +63
   preLink.Data.Security.SecurityHelper.GetUserEntity(String username, String password) in C:\Development\Prelink\prelink\src\preLink.Data\Security\SecurityHelper.cs:69
   preLink.Data.Security.SecurityHelper.GetUser(String userName) in C:\Development\Prelink\prelink\src\preLink.Data\Security\SecurityHelper.cs:124
   preLink.Web.UI.Provider.CustomMembershipProvider.ValidateUser(String username, String password) in C:\Development\Prelink\prelink\src\preLink.Web.UI\Provider\CustomMembershipProvider.cs:93
   System.Web.UI.WebControls.Login.AuthenticateUsingMembershipProvider(AuthenticateEventArgs e) +100
   System.Web.UI.WebControls.Login.OnAuthenticate(AuthenticateEventArgs e) +113
   System.Web.UI.WebControls.Login.AttemptLogin() +178
   System.Web.UI.WebControls.Login.OnBubbleEvent(Object source, EventArgs e) +134
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +56
   System.Web.UI.WebControls.Button.OnCommand(CommandEventArgs e) +107
   System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +178
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +31
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +32
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +72
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3841




--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.210 

Thanks very much for the help

Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 05-Mar-2007 15:44:59   

Hi,

after reviewing the code from FetchProjectionFromReader and CreateHashValueFromValues as suggested by your exception stack, I could not find any particular reason for that object reference exception.

Could you mention the build number of the runtime libraries you are using (the line numbers don't fit to mine)?

Also, that would be nice if you can rebuild your runtime libraries from the source code (located in the RuntimeLibraries/Sourcecode folder, you also need to remove the strong signing in assemblyinfo files) in debug mode and have your projects directly reference the source lib projects instead of the release dlls in GAC, so that you can put a breakpoint at the beginning of ProjectionUtils.CreateHashValueFromValues, and step in to identify the null variable returning the exception.

Thx

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 06-Mar-2007 10:16:52   

I also don't see why it would give a nullref exception in that particular routine, since the thing that can be null is checked first so these are weeded out. The other possibility is that the projectors are null but as shown in the code this can't be null as they're passed in.

Frans Bouma | Lead developer LLBLGen Pro
deathwish
User
Posts: 56
Joined: 07-Nov-2006
# Posted on: 06-Mar-2007 21:47:18   

Hi,

It's no big deal really. It's just used in a CustomMembershipProvider to validate a user or get the logged in user.

Thanks very much for the help.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 07-Mar-2007 10:13:09   

deathwish wrote:

Hi,

It's no big deal really. It's just used in a CustomMembershipProvider to validate a user or get the logged in user.

Thanks very much for the help.

It's still a sign that something isn't quite correct in our code so it might need attention. What I'm looking for is a way to reproduce this so it will give the error you ran into because the same routine did work in the other thread's situation where I gave it as an example... I can't spot differences though..

Frans Bouma | Lead developer LLBLGen Pro