DuplicateNameException from DataSet

Posts   
 
    
jason...
User
Posts: 14
Joined: 03-Sep-2007
# Posted on: 16-Oct-2007 08:26:27   

The CustomerEntity has two subclasses: NatureCustomerEntity and CompanyCustomerEntity. It a Target-per-entity hierarchy between these types.

I met a DuplicateNameException from the DataSet: "The DataTable has already had CustomerId column" when I was projecting any of the three types (for example EntityCollection<CustomerEntity>) to a DataSet.

If there's no any record for NatureCustomerEntity and CompanyCustomerEntity in database tables, I'll get the DataSet successfully.

            
EntityCollection<CustomerEntity> customers = new EntityCollection<CustomerEntity>(new CustomerEntityFactory());
using (DataAccessAdapter adapter = new DataAccessAdapter())
{
    adapter.FetchEntityCollection(customers, null);
}
DataSet result = new DataSet("Customers");
customers.CreateHierarchicalProjection(result);

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 16-Oct-2007 10:06:13   

Please post the complete stack trace and the LLBLGen Pro runtime library version used.

jason...
User
Posts: 14
Joined: 03-Sep-2007
# Posted on: 16-Oct-2007 12:04:52   

The version of SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll is "2.5.7.907".

Stack trace:


At System.Data.DataColumnCollection.RegisterColumnName(String name, DataColumn column, DataTable table)
At System.Data.DataColumnCollection.BaseAdd(DataColumn column)
At System.Data.DataColumnCollection.AddAt(Int32 index, DataColumn column)
At System.Data.DataColumnCollection.Add(DataColumn column)
At SD.LLBLGen.Pro.ORMSupportClasses.DataProjectorToDataTable.CreateColumns(IList projectors, Object[] rawProjectionResult)
At SD.LLBLGen.Pro.ORMSupportClasses.DataProjectorToDataTable.AddProjectionResultToContainer(IList projectors, Object[] rawProjectionResult)
At SD.LLBLGen.Pro.ORMSupportClasses.DataProjectorToDataTable.SD.LLBLGen.Pro. ORMSupportClasses.IEntityDataProjector.AddProjectionResultToContainer(List`1 propertyProjectors, Object[] rawProjectionResult)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityViewBase`1.CreateProjection(List`1 propertyProjectors, Boolean allowDuplicates, IPredicate filter, IEntityDataProjector projector)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityView2`1.CreateProjection(List`1 propertyProjectors, DataTable destination, Boolean allowDuplicates, IPredicate filter)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityView2`1.SD.LLBLGen.Pro.ORMSupportClasses.IEntityView2.CreateProjection(List`1 propertyProjectors, DataTable destination, Boolean allowDuplicates, IPredicate filter)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.CreateHierarchicalProjectionInternal(List`1 collectionProjections, DataSet destination, Dictionary`2 entitiesPerType)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.CreateHierarchicalProjection(DataSet destination)
At OrderEntryClient.Form1.ProjectDataSet() At C:\\work\\LLBLGen Pro\\OrderEntryClient\\OrderEntryClient\\Form1.cs: line 273"

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 16-Oct-2007 14:49:09   

Looks like a bug in the projector. Will check it out.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 17-Oct-2007 11:58:58   

Reproduced.

(edit) fixed in next build (10172007).

New build is attached to this post.

Frans Bouma | Lead developer LLBLGen Pro
jason...
User
Posts: 14
Joined: 03-Sep-2007
# Posted on: 19-Oct-2007 09:08:24   

Thanks a lot.

The new build has answered my first question, but my real problem was that CompanyEntity is just a relation entitiy of another OrderEntity. I didn't fetch it(CompanyEntity) alone but in prefetch paths for OrderEntity collection.


EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>(new OrderEntityFactory());
RelationPredicateBucket filter = new RelationPredicateBucket();
filter.PredicateExpression.Add(new FieldCompareValuePredicate(OrderFields.CustomerId, null, ComparisonOperator.LessEqual, 3));
IPrefetchPath2 ppath = new PrefetchPath2(EntityType.OrderEntity);
ppath.Add(OrderEntity.PrefetchPathCustomer, new CustomerEntityFactory());
ppath.Add(OrderEntity.PrefetchPathOrderItem).SubPath.Add(OrderItemEntity.PrefetchPathProduct);
using (DataAccessAdapter adapter = new DataAccessAdapter())
{
    adapter.FetchEntityCollection(orders, filter, ppath);
}
DataSet result = new DataSet("Orders");

There were two DataTables: NatureCustomerEntity and CompanyCustomerEntity in DataSet result for CustomerEntity, and I also lost the relation between OrderEntity and CompanyEntity in DataSet. That's not what I want. Although I've understood that Prefetch Paths support polymorphic access. But accessing just the super classes but not the sub classes is more often in my case. So, I have to do some extra work like below. Is there another way to do it more sensible?


DataTable dt = new DataTable("CustomerEntity");
dt.Merge(result.Tables["NatureCustomerEntity"]);
dt.Merge(result.Tables["CompanyCustomerEntity"]);
result.Tables.Add(dt);
result.Relations.Add(new DataRelation("OrderEntity_Customer", result.Tables["CustomerEntity"].Columns["CustomerId"], result.Tables["OrderEntity"].Columns["CustomerId"]));

Sorry. I have another problem pertained to this title Projetion. The scenario is that TransitionEntity has two related ActivityEntity: FromActivity and ToActivity. Method CreateHierarchicalProjection() issued an ArgumentException: "These columns have duplicated value".


EntityCollection<TransitionEntity> transitions = new EntityCollection<TransitionEntity>(new TransitionEntityFactory());
RelationPredicateBucket filter = new RelationPredicateBucket();
filter.PredicateExpression.Add(new FieldCompareValuePredicate(TransitionFields.ProcId, null, ComparisonOperator.Equal, 10000));
IPrefetchPath2 ppath = new PrefetchPath2(EntityType.TransitionEntity);
ppath.Add(TransitionEntity.PrefetchPathFromActivity);
ppath.Add(TransitionEntity.PrefetchPathToActivity);
using (DataAccessAdapter daa = new DataAccessAdapter())
{
    daa.FetchEntityCollection(transitions, filter, ppath);
}
DataSet ds = new DataSet();
transitions.CreateHierarchicalProjection(ds);

Here's its StackTrace.


At System.Data.ConstraintCollection.AddUniqueConstraint(UniqueConstraint constraint)  
At System.Data.ConstraintCollection.Add(Constraint constraint, Boolean addUniqueWhenAddingForeign)  
At System.Data.DataTable.set_PrimaryKey(DataColumn[] value)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.CreateHierarchicalProjectionInternal(List`1 collectionProjections, DataSet destination, Dictionary`2 entitiesPerType)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.CreateHierarchicalProjection(DataSet destination)

Here's the runtime library version: SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll is "2.5.7.1017" SD.LLBLGen.Pro.ORMSupportClasses.NET11.dll is "2.5.7.907"

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 19-Oct-2007 12:01:34   

jason... wrote:

Thanks a lot.

The new build has answered my first question, but my real problem was that CompanyEntity is just a relation entitiy of another OrderEntity. I didn't fetch it(CompanyEntity) alone but in prefetch paths for OrderEntity collection.


EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>(new OrderEntityFactory());
RelationPredicateBucket filter = new RelationPredicateBucket();
filter.PredicateExpression.Add(new FieldCompareValuePredicate(OrderFields.CustomerId, null, ComparisonOperator.LessEqual, 3));
IPrefetchPath2 ppath = new PrefetchPath2(EntityType.OrderEntity);
ppath.Add(OrderEntity.PrefetchPathCustomer, new CustomerEntityFactory());
ppath.Add(OrderEntity.PrefetchPathOrderItem).SubPath.Add(OrderItemEntity.PrefetchPathProduct);
using (DataAccessAdapter adapter = new DataAccessAdapter())
{
    adapter.FetchEntityCollection(orders, filter, ppath);
}
DataSet result = new DataSet("Orders");

There were two DataTables: NatureCustomerEntity and CompanyCustomerEntity in DataSet result for CustomerEntity, and I also lost the relation between OrderEntity and CompanyEntity in DataSet. That's not what I want. Although I've understood that Prefetch Paths support polymorphic access. But accessing just the super classes but not the sub classes is more often in my case. So, I have to do some extra work like below. Is there another way to do it more sensible?


DataTable dt = new DataTable("CustomerEntity");
dt.Merge(result.Tables["NatureCustomerEntity"]);
dt.Merge(result.Tables["CompanyCustomerEntity"]);
result.Tables.Add(dt);
result.Relations.Add(new DataRelation("OrderEntity_Customer", result.Tables["CustomerEntity"].Columns["CustomerId"], result.Tables["OrderEntity"].Columns["CustomerId"]));

Hierarchical projections are per type, so as the projection engine detects the different subtypes it creates per type a datatable, that's how hierarchical projections work.

I didn't completely understand your goal in this case. What you do is fetch orders and customers. You have subtypes defined for customer, so you get 3 datatables: Order, NatureCustomer and CompanyCustomer, and instead of having relations between order and these 2 customer datatables, you don't get the relations? Or is it that you DO get these relations but you want to get just 2 datatables? In the case of the latter, that isn't supported.

Sorry. I have another problem pertained to this title Projetion. The scenario is that TransitionEntity has two related ActivityEntity: FromActivity and ToActivity. Method CreateHierarchicalProjection() issued an ArgumentException: "These columns have duplicated value".


EntityCollection<TransitionEntity> transitions = new EntityCollection<TransitionEntity>(new TransitionEntityFactory());
RelationPredicateBucket filter = new RelationPredicateBucket();
filter.PredicateExpression.Add(new FieldCompareValuePredicate(TransitionFields.ProcId, null, ComparisonOperator.Equal, 10000));
IPrefetchPath2 ppath = new PrefetchPath2(EntityType.TransitionEntity);
ppath.Add(TransitionEntity.PrefetchPathFromActivity);
ppath.Add(TransitionEntity.PrefetchPathToActivity);
using (DataAccessAdapter daa = new DataAccessAdapter())
{
    daa.FetchEntityCollection(transitions, filter, ppath);
}
DataSet ds = new DataSet();
transitions.CreateHierarchicalProjection(ds);

Here's its StackTrace.


At System.Data.ConstraintCollection.AddUniqueConstraint(UniqueConstraint constraint)  
At System.Data.ConstraintCollection.Add(Constraint constraint, Boolean addUniqueWhenAddingForeign)  
At System.Data.DataTable.set_PrimaryKey(DataColumn[] value)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.CreateHierarchicalProjectionInternal(List`1 collectionProjections, DataSet destination, Dictionary`2 entitiesPerType)
At SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.CreateHierarchicalProjection(DataSet destination)

Here's the runtime library version: SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll is "2.5.7.1017" SD.LLBLGen.Pro.ORMSupportClasses.NET11.dll is "2.5.7.907"

If you fetch the graph with a Context, the FromActivity and ToActivity entity are the same entity OBJECT. Now they're two separate objects. So they're seen as two instances, and added as such, even though the entity (data) is the same.

Could you try that for me please?

Frans Bouma | Lead developer LLBLGen Pro
jason...
User
Posts: 14
Joined: 03-Sep-2007
# Posted on: 26-Oct-2007 07:49:52   

I didn't completely understand your goal in this case. What you do is fetch orders and customers. You have subtypes defined for customer, so you get 3 datatables: Order, NatureCustomer and CompanyCustomer, and instead of having relations between order and these 2 customer datatables, you don't get the relations? Or is it that you DO get these relations but you want to get just 2 datatables? In the case of the latter, that isn't supported.

For this question, I want to get just 2 datatables. So, forget it. Thanks anyway.

If you fetch the graph with a Context, the FromActivity and ToActivity entity are the same entity OBJECT. Now they're two separate objects. So they're seen as two instances, and added as such, even though the entity (data) is the same.

Could you try that for me please?

I don't quite know how to fetch the graph with a Context by FetchEntityCollection() method. Could you give me a hint for that?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 27-Oct-2007 14:06:51   

To fetch a graph with a context using fetch entity collection, you first add the collection to the context, and then fetch the collection.

It's not passing the context to the method, as it would require alot of overloads, plus the context is actually for the entities inside the collection.

so: Context c = new Context(); c.Add(myCollection); adapter.FetchEntityCollection(myCollection, filter, ... );

Frans Bouma | Lead developer LLBLGen Pro
jason...
User
Posts: 14
Joined: 03-Sep-2007
# Posted on: 29-Oct-2007 03:15:14   

You're absolutely right.

It works, Context eliminate my duplicate problem.

Thanks!