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
|
Hi LightSpeed Community, I am making a probe for our project that currently uses Linq-To-Sql and to implement/convert to a LightSpeed repository/context instead. In order for us to have no dependencies on which ORM we use, our main entities all implement their respective interfaces. ie. User -> IUser, Message -> IMessage, Transaction -> ITransaction, etc... Also since we have no idea what type of context this ORM will be using we defined our own IDataContext interface to publish methods and properties that are required to query it. In essence this is similar to your IUnitOfWork implementation and I am sure we will head into that direction eventually (Query<T>, Update, Insert, etc...). Now in my LinqToSqlContext I have a fairly basic "mapping" thingy using a Dictionary<Type, Type> so that upon construction I can register these mapped types as follows: TableMaps.Add(typeof(IUser), typeof(User)); This then allows me to use this type reference to obtain a reference to the table L2S uses by utilizing their GetTable(Type type) overload (instead of using GetTable<TEntity>()): public ITable Table<TEntity>() where TEntity : class I do not see any way for LightSpeed to give me access to the table in a generic matter other then having a Query<TEntity> extension method available. But this method (logically) insists that TEntity has an Entity constraint, but at this point my "own" TEntity is IUser and not User (IUser implements IEntity). Using the TableMaps dictionary it returns me the type User since TEntity is IUser. But I cannot pass type to Query<TEntity> of course, and there is no Query(Type type) overload, so now I am stuck? :( It seems that since the Query<TEntity> extension method already returns and IQueryable, I could bypass the Table<TEntity> method (since it's not defined on my IDataContext interface and for good reason) and use the IDataContext.Query<TEntity> instead: public IQueryable<TEntity> Query<TEntity>() where TEntity : class, IEntity But here the problem becomes even bigger since my type constraint wants IEntity, and the extension method from LightSpeed demands an Entity and ofcourse Entity does not implement IEntity, even though IEntity has an Id property just like Entity (But I understand why that won't match of course,). So my question is for the TLDR people: How can I obtain an Entity reference using UnitOfWork when dealing with interfaces instead of reference types? Please be reminded that all my IDataContext definitions have the same type constraint: where TEntity : class, IEntity This ensures that I only execute linq Expressions on types that are actually mapped (the fact that the type implements IEntity provides me with this assumption in my own code). I cannot modify my interface definition since this would impact previous and any future implementations of IDataContext when dealing with other ORM toolkits. The reason we have this setup is to ensure our IRepository and IDataContext can be used with UnitTesting to ensure our application is going to work when we switch out a new DataContext (ie. in the case where I would register LightSpeedContext within my injection container instead of LinqToSqlContext). The idea is to "just" write a new IDataContext implementation for the ORM toolkit without having the recode anything else in the application in order to use it. Sorry for not being able to describe this briefly I am horrible at making compact posts! :-) |
|
|
[quote user="Atlantez"] I meant to write: ie. in the case where I would register UnitTestContext within my injection container instead of LightSpeedContext. Because we do not want to be testing the database everytime when unit testing the individual components. |
|
|
The easiest solution is of course to allow your abstraction leak a bit, and admit a constraint such as where TEntity : Entity. But given that this will have cascading effects on your existing code, I'm guessing you're willing to accept a certain amount of isolated ugliness in order to avoid that. Here are a couple of suggestions: 1. Use the core API. The Find method has an overload that allows you to pass a Type, and has no generic constraint. So you could go uow.Find(mappedType, queryExpression);. You can then cast on the way out of that method, but that nastiness would be concealed in the repository implementation. However, there isn't a LINQ equivalent of this. 2. Use reflection to get at the LINQ generic methods while bypassing the compile-time constraint checking. Haven't tested this, but I'm thinking something like: public IQueryable<T> Query<T> where T : class, IEntity { Once again I have not tested this and make no promises. You may need a bit of trial and error to determine whether it's really a feasible approach and to get it working. |
|