3

我有一个用于参考数据项的简单界面:

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>();

但是,假设我使用IReferenceItemcalledMarket和 a的实现ReferenceItemRepository<Market>,此调用会生成如下 SQL:

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

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

MarketRepository如果我对非泛型类做同样的事情:

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

我得到了正确的 SQL:

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

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

编辑:

这似乎是特定于使用 Linq 表达式的问题;如果我将语句切换为以下内容,它会正常工作:

T item = db.QuerySingle<T>("Name = @name", new { Name = item.Name });

另一个编辑:

如果我传入IReferenceItem item我的 repo 方法而不是T item. 但这不起作用

public T Get(T item)
{
   return db.Select<T>(s => s.Name == item.Name).FirstNonDefault<T>();
}

请注意,您需要在此表中包含多个项目才能使故障明显,并且您要查找的记录必须不是查询所有记录时返回的第一个记录;否则,您将完全出于偶然的机会找回您正在寻找的那个。

4

1 回答 1

2

我没有测试使用 SelectParam 的 Select 方法,并且一切正常。下面我将我的通用存储库模式与 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; }
}
于 2013-06-13T18:10:29.773 回答