为什么Linq(表达式<func <t,bool>&gt;)在泛型类中生成不正确的Where子句?</func <t,bool>

时间:2013-06-12 21:32:19

标签: ormlite-servicestack

我有一个简单的参考数据项接口:

public interface IReferenceItem
{
    int Id { get; set; }
    string Name { get; set; }
}

我曾希望能够拥有一个能够从数据库中选择任何此类项目的ReferenceItemRepository<T> where T : IReferenceItem,如下所示:

T item = db.Select<T>(s => s.Name == item.Name).FirstNonDefault<T>();

但是,假设我使用名为IReferenceItemMarket的{​​{1}}实现,此调用会生成如下SQL:

ReferenceItemRepository<Market>

因此,它正确地解析了表及其列的名称,但Where子句变成了“Name”=“Name”,这使得它返回该表中的所有行。

如果我使用SELECT "MarketId" ,"Name" FROM "Market" WHERE ("Name" = "Name") 非泛型类做同样的事情:

MarketRepository

我得到了正确的SQL:

Market item = db.Select<Market>(s => s.Name == item.Name).FirstNonDefault<Market>();

这是ServiceStack.OrmLite中的一个错误(我用3.9.49测试过),或者我做错了什么,或者在OrmLite的实现中这是不可能的?

修改

这似乎是使用Linq表达式特有的问题;如果我将语句切换到以下语句,它可以正常工作:

SELECT "MarketId" ,"Name"  
FROM "Market"
WHERE ("Name" = 'Chicago')

另一个编辑:

如果我将T item = db.QuerySingle<T>("Name = @name", new { Name = item.Name }); 传递到我的repo方法而不是IReferenceItem item,它也会有效。但这确实工作:

T item

请注意,您需要在此表中包含多个项目才能显示失败,并且您要查找的记录必须不是查询所有记录时返回的第一个记录;否则你将会找到你正在寻找的那个。

1 个答案:

答案 0 :(得分:2)

我没有测试Select方法我使用SelectParam,一切都很完美。下面我将我的通用存储库模式与OrmLite(也许它会帮助你) - 它适用于规范模式。

public class GenericRepository<T> : IRepository<T>
    where T : class, new()
{
    private readonly IDbConnectionFactory dbConnectionFactory;

    public GenericRepository(IDbConnectionFactory dbConnectionFactory)
    {
        this.dbConnectionFactory = dbConnectionFactory;
    }

    public IEnumerable<T> FindAll()
    {
        return dbConnectionFactory.OpenDbConnection().Select<T>();
    }

    public IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate)
    {
        return dbConnectionFactory.OpenDbConnection().SelectParam<T>(predicate);
    }

    public T FindById(int id)
    {
        return dbConnectionFactory.OpenDbConnection().GetById<T>(id);
    }

    public void Update(T entity)
    {
        dbConnectionFactory.OpenDbConnection().UpdateParam(entity);
    }

    public void Remove(T entity)
    {
        dbConnectionFactory.OpenDbConnection().Delete(entity);
    }

    public T FirstOrDefault(Expression<Func<T, bool>> predicate)
    {
        return dbConnectionFactory.OpenDbConnection().FirstOrDefault(predicate);
    }

    public void Insert(T entity)
    {
        dbConnectionFactory.OpenDbConnection().InsertParam(entity);
    }



编辑: 好的我做了个例子。代码并不完美,但我的工作时间只有10分钟。 如果你想执行这个代码,那么:1)创建控制台应用程序项目2)添加对ServiceStack.OrmLite的引用 - 我使用了nuget,并且有3.9.49.0版本。我希望它会对你有所帮助。

class Program
{
    static void Main(string[] args)
    {
        //connection
        var dbFactory = new OrmLiteConnectionFactory(@"Server=.\dev;Database=survey;Trusted_Connection=True;", SqlServerDialect.Provider);

        //open connection
        IDbConnection db = dbFactory.OpenDbConnection();

        db.DropAndCreateTable<Market>();

        //create item
        var newMarket = new Market() { Id = 1, Name = "Shop", LongName = "Big Shop" };

        //add item to database
        db.InsertParam<Market>(newMarket);

        //retrive using standard way
        Console.WriteLine("Standard way");
        ShowResult(db.Select<Market>(x => x.Name == "Shop"));

        //retrive using generic repository with passing predicate to repository method
        Console.WriteLine("Generic repository with passing predicate");
        var genericRepository = new GenericRepository<Market>(dbFactory);
        ShowResult(genericRepository.FindBy(x => x.Name == "Shop"));


        //retrive using generic repository with passing specyfic value to repository method
        Console.WriteLine("Generic repository with passing specyfic value to repository method");
        var genericRepositoryWithHardcodedStatments = new GenericRepositoryWithHardcodedStatments<Market>(dbFactory);
        ShowResult(genericRepositoryWithHardcodedStatments.Find("Shop"));


        Console.WriteLine("Generic repository with passing T object to repository method");
        var genericRepositoryWithPassingT = new GenericRepositoryWithPassingT<Market>(dbFactory);
        ShowResult(genericRepositoryWithPassingT.Find(new Market()
        {
            Name = "shop"
        }));
    }

    private static void ShowResult(IEnumerable<Market> markets)
    {
        foreach (var market in markets)
        {
            Console.WriteLine(value: string.Format("{0} - {1} - {2}", market.Id, market.Name, market.LongName));
        }
    }
}

public class GenericRepository<T> where T : class, new()
{
    private readonly IDbConnectionFactory dbConnectionFactory;

    public GenericRepository(IDbConnectionFactory dbConnectionFactory)
    {
        this.dbConnectionFactory = dbConnectionFactory;
    }

    public IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate)
    {
        return dbConnectionFactory.OpenDbConnection().SelectParam<T>(predicate);
    }
}

public class GenericRepositoryWithHardcodedStatments<T> where T : IReferenceItem, new()
{
    private readonly IDbConnectionFactory dbConnectionFactory;

    public GenericRepositoryWithHardcodedStatments(IDbConnectionFactory dbConnectionFactory)
    {
        this.dbConnectionFactory = dbConnectionFactory;
    }

    public IEnumerable<T> Find(string name)
    {
        return dbConnectionFactory.OpenDbConnection().SelectParam<T>(x => x.Name == name);
    }
}

public class GenericRepositoryWithPassingT<T> where T : IReferenceItem, new()
{
    private readonly IDbConnectionFactory dbConnectionFactory;

    public GenericRepositoryWithPassingT(IDbConnectionFactory dbConnectionFactory)
    {
        this.dbConnectionFactory = dbConnectionFactory;
    }

    public IEnumerable<T> Find(T item)
    {
        return dbConnectionFactory.OpenDbConnection().SelectParam<T>(x => x.Name == item.Name);
    }
}


public interface IReferenceItem
{
    int Id { get; set; }
    string Name { get; set; }
}

public class Market : IReferenceItem
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string LongName { get; set; }
}