我试图将ASP.NET 4.5应用程序移植到.NET Core,我有一个我无法理解的真正问题。
我现有的应用程序执行存储过程,返回带有多个数据表的数据集。实体框架可以自动将返回的字段映射到我的实体属性,但只能与数据集中的第一个数据表一起使用(自然)。
所以我只是想弄清楚它是否可能以某种方式拦截模型构建过程并使用自定义代码来处理数据集并查看其他数据表以设置实体字段。
我知道我可以使用SqlConnection
直接执行存储过程的常规方法,但我想知道实体框架是否有某种方法可以执行此操作。
答案 0 :(得分:11)
目前,返回数据的the way to execute stored procedures将使用DbSet.FromSql
方法。
using (var context = new SampleContext())
{
var data= context.MyEntity
.FromSql("EXEC GetData")
.ToList();
}
这有一定的局限性:
DbSet
DbSet
类型或者你可以回归到普通的ADO.NET:
using (var context = new SampleContext())
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "GetData";
command.CommandType = CommandType.StoredProcedure;
context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
// do something with result
}
}
在某些阶段,SQL查询有plans to introduce support for returning ad hoc types。
答案 1 :(得分:0)
要回答@ DKhanaf对多个数据集的问题,可以使用SqlDataAdapter用所有结果集填充DataSet对象。 SqlDataAdapter需要完整的.NET Framework,因此您必须在面向.NET 462或类似的东西时运行.NETCore项目。
using (var context = new SampleContext())
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "GetData";
command.CommandType = CommandType.StoredProcedure;
context.Database.OpenConnection();
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
var ds = new DataSet();
adapter.Fill(ds);
return ds;
}
}
}
答案 2 :(得分:0)
我尝试了{Repository pattern}的DbFirst方法。
startup.cs
ConfigureServices(IServiceCollection services){
services.AddDbContext<AppDbContext>(opt => opt
.UseSqlServer(Configuration.GetConnectionString("SampleConnectionString")));
services.AddScoped<ISomeDAL, SomeDAL>();
}
public class AppDbContext : DbContext{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{}
}
ISomeDAl接口具有{GetPropertiesResponse GetAllPropertiesByCity(int CityId);}
public class SomeDAL : ISomeDAL
{
private readonly AppDbContext context;
public SomeDAL(AppDbContext context)
{
this.context = context;
}
public GetPropertiesResponse GetAllPropertiesByCity(int CityId)
{
//Create Required Objects for response
//wont support ref Objects through params
context.LoadStoredProc(SQL_STATEMENT)
.AddParam("CityID", CityId).Exec( r =>
{
while (r.Read())
{
ORMapping<GenericRespStatus> orm = new ORMapping<GenericRespStatus>();
orm.AssignObject(r, _Status);
}
if (r.NextResult())
{
while (r.Read())
{
Property = new Property();
ORMapping<Property> orm = new ORMapping<Property>();
orm.AssignObject(r, Property);
_propertyDetailsResult.Add(Property);
}
}
});
return new GetPropertiesResponse{Status=_Status,PropertyDetails=_propertyDetailsResult};
}
}
public class GetPropertiesResponse
{
public GenericRespStatus Status;
public List<Property> PropertyDetails;
public GetPropertiesResponse()
{
PropertyDetails = new List<Property>();
}
}
public class GenericRespStatus
{
public int ResCode { get; set; }
public string ResMsg { get; set; }
}
internal class ORMapping<T>
{
public void AssignObject(IDataReader record, T myClass)
{
PropertyInfo[] propertyInfos = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
{
if (propertyInfos.Any(obj => obj.Name == record.GetName(i))) //&& record.GetValue(i) != DBNull.Value
{
propertyInfos.Single(obj => obj.Name == record.GetName(i)).SetValue(myClass, Convert.ChangeType(record.GetValue(i), record.GetFieldType(i)));
}
}
}
}