问题描述
我更喜欢我的界面没有专门调用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(tagNames中的string tagName)
{
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。我想做一个集合?似乎像我这样回应中提到的那样,我正在混乱:
public interface IBlogDb
{
DbSet< Post>帖子{get; }
DbSet< Tag>标签{get; }
void Save();
}
最后,DbContext类
public class BlogDb:DbContext,IBlogDb
{
public BlogDb()
:base(DefaultConnection)
{
}
public DbSet< Post>帖子{get;组; }
public DbSet< Tag>标签{get;组; }
void IBlogDb.Save()
{
SaveChanges();
}
public DbSet< Comment>评论{get;组; }
public DbSet< Administrator>管理员{get;组; }
//实施IBlogDb
}
如果您接受明确的实现,并且不介意执行中的几行代码,您可以轻松地从界面中删除DbSet:
public interface IMyDbContext
{
ICollection< Customer>客户{get; }
}
public class MyDbContext:IMyContext
{
ICollection< Customer> IMyContext.Customers {get {return(ICollection< Customer>))客户; }}
public DbSet< Customer>客户{get;组; }
}
编辑:我发布了这个答案,然后重读了这个问题,然后删除了,现在回来了。这样可以让您从集合中添加/删除所需的内容。如果你想要一个额外的IQueryable,你可以用另一个接口和显式实现来分层。但是,这会变得丑陋。
你真正想要的是使用一个IDbSet并创建一个类,如DbSet的这种替换
public class MemoryDbSet< TEntity> :DbSet< TEntity>,IQueryable,
IEnumerable< TEntity>,IDbAsyncEnumerable< TEntity>
其中TEntity:class
{
private readonly Func< TEntity,object [],bool> _findSelector;
private readonly ObservableCollection< TEntity> _数据;
私有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);
返回项目;
}
public override TEntity Remove(TEntity item)
{
_data.Remove(item);
返回项目;
}
public override TEntity Attach(TEntity item)
{
_data.Add(item);
返回项目;
}
public override TEntity Create()
{
return Activator.CreateInstance< TEntity>();
}
public override TDerivedEntity创建< TDerivedEntity>()
{
return Activator.CreateInstance< TDerivedEntity>();
}
public override ObservableCollection< TEntity>本地
{
get {return _data; }
}
输入IQueryable.ElementType
{
get {return _query.ElementType;
}
表达式IQueryable.Expression
{
get {return _query.Expression;
IQueryProvider IQueryable.Provider
{
get
{
返回新的MemoryDbAsyncQueryProvider< TEntity>(_ query.Provider);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator< TEntity> IEnumerable< TEntity> .GetEnumerator()
{
return _data.GetEnumerator();
}
IDbAsyncEnumerator< TEntity> IDbAsyncEnumerable< TEntity取代。
GetAsyncEnumerator()
{
返回新的MemoryDbAsyncEnumerator< TEntity>(_ data.GetEnumerator());
}
}
I would prefer that my interface didn't call out DbSet exclusively. I was trying to make them into ICollection and IQueryable...but with IQueryable I couldn't call the "Add" method such as _db.Posts.Add(post). With ICollection whenever I called the Add method it would jump to the get statement and return a list instead of adding it as part of the ORM instructions to do an insert Query.
Any ideas? I'm lost
My controller
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();
}
Then we have the interface. I don't get why I need to call out the DbSet here. I'd like to make it a collection? Seems like I'm cluttering things up like was mentioned in this response:
ASP.NET MVC4: IQueryable does not contain a definition for 'Add'
public interface IBlogDb
{
DbSet<Post> Posts { get; }
DbSet<Tag> Tags { get; }
void Save();
}
Finally the DbContext class
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
}
You can easily remove DbSet from your interface if you embrace explicit implementation and don't mind a few extra lines of code in the implementation:
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; }
}
EDIT: I posted this answer, then reread the question, then deleted it, and now it's back. This will get you what you need as far as Add/Remove from the collection. If you want an additional IQueryable instead, you can layer it with another interface and explicit implementation. However, this gets ugly.
What you really want is to use an IDbSet and create a class, such as this replacement for 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());
}
}
这篇关于如何从我的界面删除DbSet?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!