I just wrote a little service today to do this, for my project. So far I've only done a fake store implementation. For a real implementation you would simply use a remote service method, and then on the server side execute your query to get the next id.
public interface IKeyService<T> : IHideObjectMembers { Task AllocateRange(int count); Task<T> GetNext(); }
|
public class FakeStoreIntegerKeyService : IKeyService<int> { private int _nextId; private readonly Queue<int> _availableKeys;
public FakeStoreIntegerKeyService() { _nextId = 1; _availableKeys = new Queue<int>(); }
#region Implementation of IKeyService<int>
public Task AllocateRange(int count) { for (var i = 0; i < count; i++) { _availableKeys.Enqueue(_nextId++); } return TaskFns.FromResult(true); }
public Task<int> GetNext() { if (_availableKeys.Count == 0) AllocateRange(1);
return TaskFns.FromResult(_availableKeys.Dequeue()); }
#endregion }
|
I have multiple models so I just made an interface for this specific model so I'm not sharing keys between different models. You could bypass this step.
public interface IDemoKeyService : IKeyService<int> {
}
public class DemoFakeKeyService : FakeStoreIntegerKeyService, IDemoKeyService {
}
|
I then subclassed Factory<T> to include my Key Service
public class DemoFactory<T> : Factory<T> where T : Entity { private readonly IDemoKeyService _keyService;
public DemoFactory(IEntityManagerProvider<DemoEntities> entityManagerProvider, IDemoKeyService keyService) : base(entityManagerProvider) { _keyService = keyService; }
public override async System.Threading.Tasks.Task<T> CreateAsync(System.Threading.CancellationToken cancellationToken) { var entity = await base.CreateAsync(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); var key = await _keyService.GetNext(); cancellationToken.ThrowIfCancellationRequested(); SetKey(entity, key); return await TaskFns.FromResult(entity); }
private void SetKey(T entity, int key) { var keyProperty = entity.EntityAspect.EntityMetadata.KeyProperties.FirstOrDefault(); entity.EntityAspect.SetValue(keyProperty, key); } }
|
In my sample project I have a Customer and a CustomerAddress table. Previously I could do Customer.AddAddress() but I wasn't sure the cleanest way to implement that anymore. So I simply made a new Factory class to handle this:
public class CustomerFactory : ICustomerFactory { private readonly DemoFactory<Customer> _customerFactory; private readonly DemoFactory<CustomerAddress> _customerAddressFactory;
public CustomerFactory(IEntityManagerProvider<DemoEntities> entityManagerProvider, IDemoKeyService keyService) { _customerFactory = new DemoFactory<Customer>(entityManagerProvider, keyService); _customerAddressFactory = new DemoFactory<CustomerAddress>(entityManagerProvider, keyService); }
#region Implementation of ICustomerFactory
public Task<Customer> CreateCustomer() { return _customerFactory.CreateAsync(CancellationToken.None); }
public async Task<CustomerAddress> CreateAddress(int customerId) { var address = await _customerAddressFactory.CreateAsync(); address.CustomerId = customerId; return await TaskFns.FromResult(address); }
#endregion }
|
I then expose the ICustomerFactory on my UnitOfWork. I can then simply do:
Address = await UnitOfWork.CustomerFactory.CreateAddress(Customer);
|
If Marcel has a better way of doing this, I'm all ears. Hopefully this will give you enough to get started though.
Edited by smi-mark - 03-Oct-2012 at 6:08am