通过存储过程将数据列表返回给dapper

我试图通过存储过程使用Dapper返回数据

我的DTO类与下面类似(为简洁起见,删除了一些属性)

public class CarDTO { public int CarID { get; set; } public string Manufacturer { get; set; } public List CarOptions { get; set; } } 

所以基本上在DB中我有一个CarOption表,它有一个CarID列 – 即Car可以有很多选项。

我分钟的DAL层呼叫如下:

  private string getCarDataSp = "[dbo].[GetCarData]"; public IEnumerable GetCarData(int customerId, int year) { return Get(db => db.Query(getCarDataSp , new { CustomerID = customerId, Year = year }, commandType: CommandType.StoredProcedure)); } 

我的Get函数的实现在我的BaseRepository类中:

  public T Get(Func query) { using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myDB"].ConnectionString)) { return query.Invoke(db); } } 

是否可以使用Dapper我可以从我的存储过程返回CarOptions?

我在那一刻的存储过程如下:

 ALTER PROCEDURE [dbo].[GetCarData] @CustomerID int, @Year int AS BEGIN SET NOCOUNT ON; SELECT * from [dbo].Car c JOIN [dbo].Customer cust ON c.CarID = cust.CarID WHERE cust.CustID = @CustomerID AND cust.Year = @Year END 

上面的查询可能会返回很多行以及CarID和Manufacturer以及我为Brevity删除的其他属性。 Dapper会按预期将这些映射回DTO。

但是,它是如何在存储过程中返回CarOptions列表 – 是否可以使用另一个查询或者是否应该以某种方式将其分离出来? 例如,如果我有CarID 1和CarID 2返回,CarOption表中可能有6行,CarID 1表中的CarID 1和4行,CarID 2,理想情况下,我希望它们全部返回到CarOptions集合如果可能,通过Dapper?

对的,这是可能的。 有几种方法可以用精巧的方法解决“一对多”情景:

方法1 – 返回两个查询,在DAL中组合

 ALTER PROCEDURE [dbo].[GetCarData] @CustomerID int, @Year int AS BEGIN SET NOCOUNT ON; --return cars SELECT c.* from [dbo].Car c INNER JOIN [dbo].Customer cust ON c.CarID = cust.CarID WHERE cust.CustID = @CustomerID AND cust.Year = @Year --return options SELECT opt.* from [dbo].Car c INNER JOIN [dbo].Customer cust ON c.CarID = cust.CarID INNER JOIN dbo.CarOptions opt ON op.CarID = c.CarID WHERE cust.CustID = @CustomerID AND cust.Year = @Year END 

DAL

 var multi = db.QueryMultiple(getCarDataSp , new { CustomerID = customerId, Year = year }, commandType: CommandType.StoredProcedure)); var cars = multi.Read(); var options = multi.Read(); //wire the options to the cars foreach(var car in cars){ var carOptions = options.Where(w=>w.Car.CarID == car.CarID); //I would override Equals in general so you can write w.Car.Equals(car)...do this on a common DataModel class car.Options = carOptions.ToList(); } 

方法2 – 返回一个查询,在DAL中拆分

PROC

 ALTER PROCEDURE [dbo].[GetCarData] @CustomerID int, @Year int AS BEGIN SET NOCOUNT ON; SELECT c.*, opt.* from [dbo].Car c INNER JOIN [dbo].Customer cust ON c.CarID = cust.CarID LEFT OUTER JOIN dbo.CarOptions opt ON op.CarID = c.CarID WHERE cust.CustID = @CustomerID AND cust.Year = @Year END 

DAL

 var tuples = db.Query>(getCarDataSp , new { CustomerID = customerId, Year = year }, (car,opt)=> Tuple.Create(car,opt), commandType: CommandType.StoredProcedure); //group tuples by car var cars = tuple.GroupBy(gb=>gb.Item1.CarID) //again, overriding equals makes it so you can just to GroupBy(gb=>gb.Item1) .Select(s=>{ var car = s.First().Item1; var carOptions = s.Select(t=>t.Item2).ToList() return car; }); 

增强function

在查询中使用临时表

这会将所有按参数过滤放入单个查询中。 后续查询是ID的简单选择。

 ALTER PROCEDURE [dbo].[GetCarData] @CustomerID int, @Year int AS BEGIN SET NOCOUNT ON; declare @t table(CarID int); --filter cars (only deal with parameters here) INSERT INTO @t(CarID) SELECT c.CarID FROM dbo.Car c INNER JOIN [dbo].Customer cust ON c.CarID = cust.CarID WHERE cust.CustID = @CustomerID AND cust.Year = @Year --return cars SELECT c.* FROM [dbo].Car c INNER JOIN @tt ON t.CarID = c.CarID --return options SELECT opt.* FROM dbo.CarOptions opt INNER JOIN @tt ON t.CarID = opt.CarID END 

应用BaseDTO来帮助实现平等

一旦你有了BaseDTO,并连接了你的ID,你可以简单地说出诸如:cars.Where(w => w.Equals(car)),字典[car](如果它在那里),if(car.Equals) (otherCar))或results.GroupBy(gb => gb.Car)…

 public class BaseDTO { internal int ID { get; set; } ///  /// If the obj is the same type with the same id we'll consider it equal. ///  public override bool Equals(object obj) { if(obj == null || this.GetType() != obj.GetType()) { return false; } return this.GetType().GetHashCode() == obj.GetType().GetHashCode() && this.ID == (BaseDTO)obj.ID; } ///  /// If you override equals, you should override gethashcode. /// http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode#263416 ///  public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + this.GetType().GetHashCode(); hash = hash * 23 + this.ID; return hash; } } } public class CarDTO : BaseDTO { public int CarID { get { return this.ID; } set { this.ID = value; } } public string Manufacturer { get; set; } public List CarOptions { get; set; } }