我有一个简单的参考数据项接口:
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>();
但是,假设我使用名为IReferenceItem
和Market
的{{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
请注意,您需要在此表中包含多个项目才能显示失败,并且您要查找的记录必须不是查询所有记录时返回的第一个记录;否则你将会找到你正在寻找的那个。
答案 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; }
}