- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
SaveMulti Concurrency issues
Joined: 30-Apr-2007
Northwind type demo
I have a screen where a comboboxes datasource is set to a CustomerCollection.GetMulti(null). When the user picks a customer, set an order DataGridView.Datasource = that customer.orders as well as a ordertail datagridview.datasource, then I set the datamember for the order details to "OrderDetails.
Everything works fine, but now I am trying to add some concurrency control in there. I have read the newsgroup and created a class copied from the newsgroup:
private class OrderConcurrencyFilterFactory : IConcurrencyPredicateFactory
{
public IPredicateExpression CreatePredicate(
ConcurrencyPredicateType predicateTypeToCreate, object containingEntity)
{
IPredicateExpression toReturn = new PredicateExpression();
OrdersEntity order = (OrdersEntity)containingEntity;
switch (predicateTypeToCreate)
{
case ConcurrencyPredicateType.Delete:
toReturn.Add(OrdersFields.OrderDate == order.Fields[(int)OrdersFieldIndex.OrderDate].DbValue);
break;
case ConcurrencyPredicateType.Save:
// only for updates
toReturn.Add(OrdersFields.OrderDate == order.Fields[(int)OrdersFieldIndex.OrderDate].DbValue);
break;
}
return toReturn;
}
}
I am just testing, OrderDate is not something I would usually choose. I have called Customer.Orders.ConcurrencyPredicateFactoryToUse = new OrderConcurrencyFilterFactory();
in a couple places, and set a breakpoint within the CreatePredicate, but it is never hit and my updates viewed through Query Profiler do not have the order date in the where condition. I am thinking I am not setting the predicatefactory in the correct place. I saw another thread where they set it on an orders collection before filling it, but here I just have a customer that I am filling. Any ideas? Hopefully I have made what I am doing clear enough. Thanks!
Chad
Please read this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=8532
Note that you should download the latest libraries. Also you should set the ConcurrencyPredicateFactoryToUse before the collection get filled. Please LLBLGenPro Help - Using generated code - SelfServicing - Using the entity classes - Concurrency control for some lights about setting the ConcurrencyPredicateFactoryToUse by default in your entityClasses.
Joined: 30-Apr-2007
daelmo wrote:
Please read this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=8532
Note that you should download the latest libraries. Also you should set the ConcurrencyPredicateFactoryToUse before the collection get filled. Please LLBLGenPro Help - Using generated code - SelfServicing - Using the entity classes - Concurrency control for some lights about setting the ConcurrencyPredicateFactoryToUse by default in your entityClasses.
Thanks! That is the thread I was reading, and I think the biggest question is when to I set the factory to use. As I said, I am filling the combo box with CustomerCollection.GetMulti(). This creates my customer collection, and they have an orders collection already - so how can I set the concurrencyfactory before that?
When the combo box item changes, I get the current customer item and set the datagrids values to the order and orderdetails. This is where I have tried setting the concurrency factory, but it did not work. I would think I have the latest libraries and such as that thread was from january and I downloaded this product in the last 30 days.
Chad, The think is that when you state:
Customer.Orders.ConcurrencyPredicateFactoryToUse = new OrderConcurrencyFilterFactory();
two things happen:
-
The Customer.Orders Collection is filled.
-
_ConcurencyPredicateFactoryToUse _is set to the collection, so new entities added to the collection will have the ConcurencyPredicateFactoryToUse you specify, according to this (LLBGenPro Help):
You can also set an IConcurrencyPredicateFactory instance of an entity using the ConcurrencyPredicateFactoryToUse property of an EntityCollection to automatically set the ConcurrencyPredicateFactoryToUse property of an entity when it's added to the particular entity collection.
BUT the entities had already added in step 1. So at this point none of all entities have ConcurencyPredicateFactoryToUse!
You can achieve the _ConcurencyPredicateFactoryToUse _for an _EntityCollection _in many ways when you are using SelfServicing:
A. Set _ConcurrencyPredicateFactoryToUse _before the collection get filled. Recommended if you dont want to set by default a ConcurrencyPredicateFactoryToUse and you can use an EntityCollection variable (not Entity.EntityCollection reference).
// collection to fill
OrdersCollection ordersFromALFKI = new OrdersCollection();
// set the custom concurrency control class
ordersFromALFKI.ConcurrencyPredicateFactoryToUse = new OrdersConcurrencyFilterFactory();
// fetch the data
ordersFromALFKI.GetMulti(OrdersFields.CustomerId == "ALFKI");
// changes some values
ordersFromALFKI[0].EmployeeId = 6;
// update data
ordersFromALFKI.SaveMulti();
B. Set _ConcurrencyPredicateFactoryToUse _for each entity just fetched. Recommended if you dont want to set by default a ConcurrencyPredicateFactoryToUse and you can't use an EntityCollection variable (you need to reference Entity.EntityCollection directly).
// customer in action
CustomersEntity customer = new CustomersEntity("ALFKI");
// setting custom concurrency control class for each entity fetched
foreach (OrdersEntity order in customer.Orders)
{
order.ConcurrencyPredicateFactoryToUse = new OrdersConcurrencyFilterFactory();
}
// changes some values
customer.Orders[0].EmployeeId = 6;
// update data
customer.Orders.SaveMulti();
C. Setting _ConcurrencyPredicateFactoryToUse _by default at GetConcurrencyPredicate Recommended if you want to set by default a ConcurrencyPredicateFactoryToUse and you want use Entity.EntityCollection directly.
using Northwind;
using SD.LLBLGen.Pro.ORMSupportClasses;
namespace Northwind.EntityClasses
{
public partial class OrdersEntity
{
// overrides the ConcurrencyFactory delivery
public override IPredicateExpression GetConcurrencyPredicate(ConcurrencyPredicateType predicateTypeToCreate)
{
return new OrdersConcurrencyFilterFactory().CreatePredicate(predicateTypeToCreate, this);
}
}
}
/// customer in action (note that no ConcurrencyPredicateFactoryToUse code is needed at all)
CustomersEntity customer = new CustomersEntity("ALFKI");
// changes some values
customer.Orders[0].EmployeeId = 6;
// update data
customer.Orders.SaveMulti();
D. Setting _ConcurrencyPredicateFactoryToUse _by default at OrdersEntityFactory.Create() method at EntityFactories.cs file. Recommended if you want to set by default a ConcurrencyPredicateFactoryToUse and you want use Entity.EntityCollection directly.
/// <summary>Creates a new, empty OrdersEntity object.</summary>
/// <returns>A new, empty OrdersEntity object.</returns>
public virtual IEntity Create()
{
IEntity toReturn = new OrdersEntity();
// __LLBLGENPRO_USER_CODE_REGION_START CreateNewOrders
toReturn.ConcurrencyPredicateFactoryToUse = new OrdersConcurrencyFilterFactory();
// __LLBLGENPRO_USER_CODE_REGION_END
return toReturn;
}
/// customer in action (note that no ConcurrencyPredicateFactoryToUse code is needed at all)
CustomersEntity customer = new CustomersEntity("ALFKI");
// changes some values
customer.Orders[0].EmployeeId = 6;
// update data
customer.Orders.SaveMulti();
E. Modify the template, so the above line in option D (toReturn.ConcurrencyPredicateFactoryToUse = new OrdersConcurrencyFilterFactory() ) is always generated (this include all entities). For this option read this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=2316 Recommended if all your entities have similar approaches (use concurrency control) and you have an IConcurrencyPredicateFactory for each one.
So in your case I recommend you option C, if you always use the concurrency control for that entity. You only need to override the _GetConcurrencyPredicate _method and forget about setting _ConcurrencyPredicateFactoryToUse _at all
Hope helpful
Joined: 30-Apr-2007