我正在尝试为我的实体编写一些通用的LINQ查询,但是在处理更复杂的事情时遇到了问题。现在我正在使用一个包含所有泛型的EntityDao类,并且每个对象类Daos(例如Accomplishments Dao)都继承它,例如:
using LCFVB.ObjectsNS;
using LCFVB.EntityNS;
namespace AccomplishmentNS
{
public class AccomplishmentDao : EntityDao<Accomplishment>{}
}
现在我的entityDao有以下代码:
using LCFVB.ObjectsNS;
using LCFVB.LinqDataContextNS;
namespace EntityNS
{
public abstract class EntityDao<ImplementationType> where ImplementationType : Entity
{
public ImplementationType getOneByValueOfProperty(string getProperty, object getValue)
{
ImplementationType entity = null;
if (getProperty != null && getValue != null) {
//Nhibernate Example:
//ImplementationType entity = default(ImplementationType);
//entity = Me.session.CreateCriteria(Of ImplementationType)().Add(Expression.Eq(getProperty, getValue)).UniqueResult(Of InterfaceType)()
LCFDataContext lcfdatacontext = new LCFDataContext();
//Generic LINQ Query Here
lcfdatacontext.GetTable<ImplementationType>();
lcfdatacontext.SubmitChanges();
lcfdatacontext.Dispose();
}
return entity;
}
public bool insertRow(ImplementationType entity)
{
if (entity != null) {
//Nhibernate Example:
//Me.session.Save(entity, entity.Id)
//Me.session.Flush()
LCFDataContext lcfdatacontext = new LCFDataContext();
//Generic LINQ Query Here
lcfdatacontext.GetTable<ImplementationType>().InsertOnSubmit(entity);
lcfdatacontext.SubmitChanges();
lcfdatacontext.Dispose();
return true;
}
else {
return false;
}
}
}
}
我已经使insertRow函数工作,但是我甚至不确定如何去做getOnebyValueOfProperty,我在这个网站上找到的最接近的东西是:
如何使用我当前的设置传递列名和我正在检查的值?从使用where谓词开始,这似乎是不可能的,因为实体类在传递它们之前不知道任何属性是什么。
最后,我需要一些方法来设置一个新对象作为设置为实现类型的返回类型,在nhibernate中(我想要转换的内容)只是这一行做到了:
ImplentationType entity = default(ImplentationType);
但是default是一个nhibernate命令,我该如何为LINQ做这个?
修改
即使离开基类,getOne似乎也不起作用(这是自动生成的LINQ类的部分类)。我甚至删除了泛型。我试过了:namespace ObjectsNS
{
public partial class Accomplishment
{
public Accomplishment getOneByWhereClause(Expression<Action<Accomplishment, bool>> singleOrDefaultClause)
{
Accomplishment entity = new Accomplishment();
if (singleOrDefaultClause != null) {
LCFDataContext lcfdatacontext = new LCFDataContext();
//Generic LINQ Query Here
entity = lcfdatacontext.Accomplishments.SingleOrDefault(singleOrDefaultClause);
lcfdatacontext.Dispose();
}
return entity;
}
}
}
收到以下错误:
Error 1 Overload resolution failed because no accessible 'SingleOrDefault' can be called with these arguments:
Extension method 'Public Function SingleOrDefault(predicate As System.Linq.Expressions.Expression(Of System.Func(Of Accomplishment, Boolean))) As Accomplishment' defined in 'System.Linq.Queryable': Value of type 'System.Action(Of System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean))' cannot be converted to 'System.Linq.Expressions.Expression(Of System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean))'.
Extension method 'Public Function SingleOrDefault(predicate As System.Func(Of Accomplishment, Boolean)) As Accomplishment' defined in 'System.Linq.Enumerable': Value of type 'System.Action(Of System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean))' cannot be converted to 'System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean)'. 14 LCF
好的,我改变了没问题:
public Accomplishment getOneByWhereClause(Expression<Action<Accomplishment, bool>> singleOrDefaultClause)
为:
public Accomplishment getOneByWhereClause(Expression<Func<Accomplishment, bool>> singleOrDefaultClause)
错误消失了。好吧,但现在当我尝试通过以下方式调用方法时:
Accomplishment accomplishment = new Accomplishment();
var result = accomplishment.getOneByWhereClause(x=>x.Id = 4)
它没有用,它说x没有声明。
我也试过
getOne<Accomplishment>
Expression<Func<
Expression<Action<
以各种格式,但参数未被正确识别为函数调用中的表达式,或者它无法将我作为参数的类型转换为singleofDefault()中使用的类型。所以这两个错误就像上面那样。班级成就确实有ID。最后我还尝试将x声明为新的成就,因此它将被声明,此时代码会更改=&gt; to&gt; =自动说:
Error 1 Operator '>=' is not defined for types 'LCFVB.ObjectsNS.Accomplishment' and 'Integer'.
=(
答案 0 :(得分:2)
如果我理解你想要的东西,你所链接的问题就会描述(某种程度上)你需要做什么。
public ImplementationType getOne(Expression<Func<ImplementationType , bool> singleOrDefaultClause)
{
ImplementationType entity = null;
if (singleOrDefaultClause != null)
{
LCFDataContext lcfdatacontext = new LCFDataContext();
//Generic LINQ Query Here
entity = lcfdatacontext.GetTable<ImplementationType>().SingleOrDefault(singleOrDefaultClause);
lcfdatacontext.Dispose();
}
return entity;
}
当你调用这个方法时,它看起来像
//note assumption that ConcreteClass DAO has member called Id
var myEntity = ConcreteClass.getOne(x=>x.Id == myIdVariable);
我没有编译这个,所以我不能说它是100%正确,但这个想法有效。我正在使用类似的东西,除了我定义我的方法是通用的基类来实现公共代码。
<强>更新强> 难道你不能只使用new来创建你需要的类的实例吗?如果你需要更通用的东西,那么我认为你将不得不使用反射来调用构造函数。对不起,如果我误解了你的要求。
更新以回应其他详细信息的评论 扩展更新POCO:有很多方法可以做到这一点,但一种方法是从表达式中获取PropertyInfo并调用setter。 (可能更好的方法来做到这一点,但我还没想出来。)例如它看起来像:
protected internal bool Update<TRet>(Expression<Func<T, TRet>> property, TRet updatedValue)
{
var property = ((MemberExpression)member.Body).Member as PropertyInfo;
if (property != null)
{
property.SetValue(this, updatedValue, null);
return true;
}
return false;
}
注意:我从我的代码库中删除了这个(删除了一些其他东西)我正在工作的项目。此方法是我所有POCO实现的基类的一部分。可编辑基类和我的POCO的基类位于同一个程序集中,因此Editable可以将其作为内部方法调用。
我的方法有效,但我更喜欢你的方法,因为它允许多个参数更灵活,但我真的很想把它保存在我的DAO中。除了一个之外,在我的DAO中使用所有db方法会有点令人困惑。设置函数是getOne吗?
我不确定我明白你在问我什么。是的,您可以将getOne
函数设置为通用方法,这实际上是我所做的,尽管我已经更进一步,并且所有方法都是通用的。这简化了我的UI / BL界面边界,到目前为止至少具有足够的表现力/灵活性,可以覆盖我的所有使用要求,而无需进行重大更改。如果它有帮助我已经包含BL对象实现和暴露给UI的接口。我的DAL本质上是NHibernate所以我没有任何东西可以告诉你那里。
public interface ISession : IDisposable
{
bool CanCreate<T>() where T : class,IModel;
bool CanDelete<T>() where T : class, IModel;
bool CanEdit<T>() where T : class, IModel;
bool CanGet<T>() where T : class, IModel;
T Create<T>(IEditable<T> newObject) where T:class,IModel;
bool Delete<T>(Expression<Func<T, bool>> selectionExpression) where T : class, IModel;
PageData<T> Get<T>(int page, int numberItemsPerPage, Expression<Func<T, bool>> whereExpression) where T : class, IModel;
PageData<T> Get<T, TKey>(int page, int numberItemsPerPage, Expression<Func<T, bool>> whereExpression, Expression<Func<T, TKey>> orderBy, bool isAscending) where T : class, IModel;
T Get<T>(Expression<Func<T, bool>> selectionExpression) where T : class, IModel;
IEnumerable<T> GetAllMatches<T>(Expression<Func<T, bool>> whereExpression) where T : class, IModel;
IEditable<T> GetForEdit<T>(Expression<Func<T, bool>> selectionExpression) where T : class, IModel;
IEditable<T> GetInstance<T>() where T : class, IModel;
IQueryable<T> Query<T>() where T : class, IModel;
bool Update<T>(IEditable<T> updatedObject) where T : class, IModel;
}