我正在为一个配置应用程序包装一个通用的SQL表编辑器,使用Entity Framework,一个Repository模式,依此类推。层上可能有点矫枉过正。在任何情况下,我都有一个通用的MVC控制器(我们称之为MyController),希望将其调用发送到通用服务层(MyServices),其中“T”的所有内容都是直接表示SQL表的一些数据模型类。每个数据模型类都有一个名为“Id”的ident字段,它是从一个基本模型(它本身正在实现一个接口)实现的。
一切都非常简单和流畅,除非我需要在数据集上调用FindBy选项,我必须提供一个委托来搜索泛型类型的东西。我知道类型约束需要附加一个接口,以便我可以访问任何类型T中的“Id”字段,但这样做会导致与显式实现通用控制器的任何控制器发生冲突。所以:
通用服务层:
public abstract class MyServices<T> : IMyService<T> where T : class, new()
{
IMyRepository<T> _MyRepository;
public MyServices(IMyRepository<T> MyRepository)
{
_MyRepository = MyRepository;
}
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
return _MyRepository.FindBy(predicate);
}
}
通用存储库:
public partial class MyRepository<T> : IMyRepository<T> where T : class, new()
{
MyTablesEntities _entities = new MyTablesEntities();
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _entities.Set<T>().Where(predicate);
return query;
}
}
通用控制器:
public class MyController<T> : Controller where T : class, new()
{
private string ViewTitle = typeof(T).ToString();
private readonly IMyServices<T> _MyServices = default(IMyServices<T>);
public MyController() { }
public MyController(IMyServices<T> mtt)
{
_MyServices = mtt;
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
T editItem = _MyServices.FindBy(c => **c.Id == id**).SingleOrDefault();
if (editItem == null)
{
return HttpNotFound();
}
return PartialView(editItem);
}
}
和使用MyController的Controller:
public class AccountsController : MTTablesController<Accounts>
{ }
显然,使用此设置,FindBy委托子句无法区分T的类型直到运行时,因此无法以这种方式编译,给出:
'T'不包含'Id'的定义,也没有扩展方法'Id'可以找到'T'类型的第一个参数
但是,如果我将包含“Id”属性的接口(IMyTableEntity)添加到通用控制器的约束中:
public class MyController<T> : Controller where T : class, MyTables.DataAccess.Metadata.Base.IMyTableEntity, new()
public interface IMyTableEntity
{
int Id { get; set; }
}
我现在在执行控制器上得到了这个错误:
类型'MyTables.DataAccess.Account'不能在泛型类型或方法'MyController'中用作类型参数'T'。没有从“MyTables.DataAccess.Account”到“MyTables.DataAccess.Metadata.Base.IMyTableEntity”的隐式引用转换。
我陷入了僵局,因为这两个错误都让我重新尝试了另一种方式,这两种方式都没有效果。我需要通用控制器上的通用“T”足够智能,随身携带Id字段,而不会混淆上面的实现控制器。
答案 0 :(得分:0)
trailmax可能已找到它......
您的班级'MyTables.DataAccess.Account'必须实现IMyTableEntity
我的数据建模以这种方式设置:
EF基础部分类:
public partial class Accounts {
public int Id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
包含数据注释的元数据模型:
public class AccountsMetadata : MyTables.DataAccess.Metadata.Base.MyTableEntity {
[Key]
[Required]
[UniqueValidator]
public string Code { get; set; }
[Display(Name="Description")]
[StringLength(100)]
public string Description { get; set; }
}
将他们联系在一起的引导程序
[MetadataType(typeof(AccountsMetadata))]
public partial class Accounts { }
我需要做的是将接口的实现添加到每个部分的bootstrap定义中,即:
[MetadataType(typeof(AccountsMetadata))]
public partial class Accounts : MyTables.DataAccess.Metadata.Base.IMyTableEntity { }
然后通过将IMyTableEntity接口设置为通用控制器中T的约束来跟进,如上所述......