[英]How to remove DbSet from my interface?
我希望我的界面不专门调出DbSet。 我试图将它们设置为ICollection和IQueryable ...,但是使用IQueryable,我无法调用“添加”方法,例如_db.Posts.Add(post)。 使用ICollection时,每当我调用Add方法时,它都会跳转到get语句并返回一个列表,而不是将其作为ORM指令的一部分添加以执行插入查询。
有任何想法吗? 我迷路了
我的控制器
private readonly IBlogDb _db;
public PostsController(IBlogDb db)
{
_db = db;
}
public ActionResult Update(int? id, string title, string body, DateTime date, string tags)
{
if (!IsAdmin)
{
RedirectToAction("Index");
}
if (ModelState.IsValid)
{
Post post = GetPost(id);
post.Title = title;
post.Body = body;
post.Date = date;
post.Tags.Clear();
tags = tags ?? string.Empty;
string[] tagNames = tags.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string tagName in tagNames)
{
post.Tags.Add(GetTag(tagName));
}
if (!id.HasValue || id == 0)
{
_db.Posts.Add(post);
_db.Save();
}
_db.Save();
return RedirectToAction("Details", new { id = post.Id });
}
return View();
}
然后我们有了界面。 我不明白为什么我需要在这里调出DbSet。 我想收藏吗? 似乎我正在把事情弄乱,就像在此响应中提到的那样:
ASP.NET MVC4:IQueryable不包含“添加”的定义
public interface IBlogDb
{
DbSet<Post> Posts { get; }
DbSet<Tag> Tags { get; }
void Save();
}
最后是DbContext类
public class BlogDb : DbContext, IBlogDb
{
public BlogDb()
: base("DefaultConnection")
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
void IBlogDb.Save()
{
SaveChanges();
}
public DbSet<Comment> Comments { get; set; }
public DbSet<Administrator> Administrators { get; set; }
//Implementing IBlogDb
}
如果您接受显式实现并且不介意实现中多了几行代码,则可以轻松地从界面中删除DbSet:
public interface IMyDbContext
{
ICollection<Customer> Customers { get; }
}
public class MyDbContext : IMyContext
{
ICollection<Customer> IMyContext.Customers { get { return (ICollection<Customer>)Customers; } }
public DbSet<Customer> Customers { get; set; }
}
编辑:我发布了这个答案,然后重新阅读该问题,然后将其删除,现在又回来了。 从集合中,这将为您提供所需的“添加/删除”。 如果要使用其他IQueryable,则可以使用另一个接口和显式实现对其进行分层。 但是,这很难看。
您真正想要的是使用IDbSet并创建一个类,例如DbSet的替代品
public class MemoryDbSet<TEntity> : DbSet<TEntity>, IQueryable,
IEnumerable<TEntity>, IDbAsyncEnumerable<TEntity>
where TEntity : class
{
private readonly Func<TEntity, object[], bool> _findSelector;
private readonly ObservableCollection<TEntity> _data;
private readonly IQueryable _query;
public MemoryDbSet(Func<TEntity, object[], bool> findSelector)
{
_findSelector = findSelector;
_data = new ObservableCollection<TEntity>();
_query = _data.AsQueryable();
}
public override TEntity Find(params object[] keyValues)
{
return _data.SingleOrDefault(item => _findSelector(item, keyValues));
}
public override TEntity Add(TEntity item)
{
_data.Add(item);
return item;
}
public override TEntity Remove(TEntity item)
{
_data.Remove(item);
return item;
}
public override TEntity Attach(TEntity item)
{
_data.Add(item);
return item;
}
public override TEntity Create()
{
return Activator.CreateInstance<TEntity>();
}
public override TDerivedEntity Create<TDerivedEntity>()
{
return Activator.CreateInstance<TDerivedEntity>();
}
public override ObservableCollection<TEntity> Local
{
get { return _data; }
}
Type IQueryable.ElementType
{
get { return _query.ElementType; }
}
Expression IQueryable.Expression
{
get { return _query.Expression; }
}
IQueryProvider IQueryable.Provider
{
get
{
return new MemoryDbAsyncQueryProvider<TEntity>(_query.Provider);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
{
return _data.GetEnumerator();
}
IDbAsyncEnumerator<TEntity> IDbAsyncEnumerable<TEntity>.
GetAsyncEnumerator()
{
return new MemoryDbAsyncEnumerator<TEntity>(_data.GetEnumerator());
}
}
您不应该做自己正在做的事情!
public class DbContextFactory : IDbContextFactory<BlogDb>
{
public BlogDb Create()
{
return new BlogDb();
}
}
然后将其注入您的控制器:
public class MyController : Controller
{
private readonly IDbContextFactory<BlogDb> blogContextFactory;
public MyController(IDbContextFactory<BlogDb> blogContextFactory)
{
this.blogContextFactory = blogContextFactory;
}
}
然后,在您的方法中,您应该正确处理上下文:
public ActionResult SaveRecord(FormCollection formStuff)
{
if (ModelState.IsValid)
{
try
{
using ( var context = blogContextFactory.Create())
{
// do you stuff here!
}
}
}
}
原因是您不想让数据库连接保持打开状态!
现在您已经正确使用了context
,可以为自己创建一个公开该方法的服务,在该服务中您可以隐藏上下文实现。
public class MyService : IMyService
{
private readonly IDbContextFactory<BlogDb> blogContextFactory;
public MyService(IDbContextFactory<BlogDb> blogContextFactory)
{
this.blogContextFactory = blogContextFactory;
}
public void CreateBlog(FormCollection formStuff) {};
public void UpdateBlog() {};
public IQueryable<Blog> Retrieve(Func<Blog, bool> predicate)
{
return this.context.Blogs.Where(predicate);
}
}
所以IMyService
是您的控制器将与之交互的对象,因此它的名称为接口或协定。 因此,这是您要公开用于处理博客上下文的方法的地方:
public interface IMyService
{
void CreateBlog(Blog blog); // you can have what ever passed through to the create, a viewModel, a DTO model or the Domain model. Personally I choose the DTO model.
void UpdateBlog(Blog blog);
void DeleteBlog(Guid id);
IQueryable<Blog> RetreiveBlogs(Func<Blog, bool> predicate); // the predicate allows you to do a quick query if you want to
}
因此,请在您的控制器中执行以下操作:
public class MyController : Controller
{
private readonly IMyService blogService;
public MyController(IMyService blogService)
{
this.blogService= blogService;
}
public ActionResult SaveRecord(FormCollection formStuff)
{
if (ModelState.IsValid)
{
try
{
this.blogService.CreateBlog(formStuff);
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.