How implement generic repository against mongodb? - c#

I am new to mongodb and I am working on mvc4 web application for a new project.
I want to use repository pattern that will talk to a mongodb context for database level communications.
Simple interface that I have used with Entity Framework 4.0 is following. The find members are the problematic area for me. I don't have a clue how to proceed with them with mongodb context.
public interface IRepository<T> where T : class
{
void Add(T entity);
void Remove(T entity);
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
//IQueryable<T> FindAll();
}
I have a very simple model that is called Hero its drive from ImongoEntity which provides a member called accessId.
public class Hero : MongoDB.Kennedy.IMongoEntity
{
public ObjectId _id { get; set; }
public string Name { get; set; }
public string Alias { get; set; }
public string _accessId { get; set;}
}
Context class is very simple you can see the collection of Heros exposted as IQueryable property.
public class MongoDataConetext: MongoDB.Kennedy.ConcurrentDataContext
{
public MongoDataConetext(string databaseName, string serverName="localhost") : base(databaseName, serverName)
{
}
public IQueryable<Hero> Heros {
get {
return base.GetCollection<Hero>().AsQueryable();
}
}
}
Now in my repository most simple methods are add and remove they successfully talk to mongodb context and get entities added or deleted from mongodb. Find method however gives me compiler level errors. I need help for my find and find all method. I am using genrics because I need my repositry class for enties like hero, solution, project, user and category.
public class Repository<T> : IRepository<T> where T : class, IMongoEntity
{
private readonly MongoDataConetext _ctx;
public Repository(MongoDataConetext ctx)
{
_ctx = ctx;
}
public void Add(T entity)
{
_ctx.Save(entity);
}
public void Remove(T entity)
{
_ctx.Delete(entity);
}
public IQueryable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
_ctx.Heros.Where(predicate);
//throw new NotImplementedException();
}
//public IQueryable<T> FindAll()
//{
// throw new NotImplementedException();
//}
}

If you are interested in an implementation similar to Rob Connery's and NBlog storage code but using the mongodb csharp driver 2.0 (that is asynchronous), you can look at:
https://github.com/alexandre-spieser/mongodb-generic-repository
You can then write a custom repository inheriting from BaseMongoRepository.
public interface ITestRepository : IBaseMongoRepository
{
void DropTestCollection<TDocument>();
void DropTestCollection<TDocument>(string partitionKey);
}
public class TestRepository : BaseMongoRepository, ITestRepository
{
public TestRepository(string connectionString, string databaseName) : base(connectionString, databaseName)
{
}
public void DropTestCollection<TDocument>()
{
MongoDbContext.DropCollection<TDocument>();
}
public void DropTestCollection<TDocument>(string partitionKey)
{
MongoDbContext.DropCollection<TDocument>(partitionKey);
}
}
Update: It is now available as its own nuget package:
Install-Package MongoDbGenericRepository

It looks like you're trying to use LINQ against your collections. That's perfect. You can do this much easier if you just expose an IQueryable property rather than write a Find() method.
Here's an example from you sample above:
public class HeroRepository : IRepository<Heros> where T : class, IMongoEntity
{
// ...
public IQueryable<Heros> Heros
{
get
{
return _ctx.GetCollection<Heros>().AsQueryable();
// Careful there, doing this from memory, may be a little off...
}
}
}
Of course, then when you consume this class, just do:
var r = new HeroRepository();
var heros = r.Heros.Where(r => r.SuperPowerLevel > 20);

Generic
public class MongoDatabase<T> : IDatabase<T> where T : class, new()
{
private static string connectionString = "connectionString";
private static IMongoClient server = new MongoClient(connectionString);
private string collectionName;
private IMongoDatabase db;
protected IMongoCollection<T> Collection
{
get
{
return db.GetCollection<T>(collectionName);
}
set
{
Collection = value;
}
}
public MongoDatabase(string collection)
{
collectionName = collection;
db = server.GetDatabase(MongoUrl.Create(connectionString).DatabaseName);
}
public IMongoQueryable<T> Query
{
get
{
return Collection.AsQueryable<T>();
}
set
{
Query = value;
}
}
public T GetOne(Expression<Func<T, bool>> expression)
{
return Collection.Find(expression).SingleOrDefault();
}
public T FindOneAndUpdate(Expression<Func<T, bool>> expression, UpdateDefinition<T> update, FindOneAndUpdateOptions<T> option)
{
return Collection.FindOneAndUpdate(expression, update, option);
}
public void UpdateOne(Expression<Func<T, bool>> expression, UpdateDefinition<T> update)
{
Collection.UpdateOne(expression, update);
}
public void DeleteOne(Expression<Func<T, bool>> expression)
{
Collection.DeleteOne(expression);
}
public void InsertMany(IEnumerable<T> items)
{
Collection.InsertMany(items);
}
public void InsertOne(T item)
{
Collection.InsertOne(item);
}
}
İnterface
public interface IDatabase<T> where T : class, new()
{
IMongoQueryable<T> Query { get; set; }
T GetOne(Expression<Func<T, bool>> expression);
T FindOneAndUpdate(Expression<Func<T, bool>> expression, UpdateDefinition<T> update, FindOneAndUpdateOptions<T> option);
void UpdateOne(Expression<Func<T, bool>> expression, UpdateDefinition<T> update);
void DeleteOne(Expression<Func<T, bool>> expression);
void InsertMany(IEnumerable<T> items);
void InsertOne(T item);
}

I know that It's a quite old post, but I would like to share with you the MongoRepository project implemented at Github or download as a NuGet package
Note: One of the problem that I had trying to implement the MongoDB Repository has been the different behaviour depending on the MongoDB driver version or wich is more or less the same, the .NET Framework. The MongoRepository project (in the link above) has solved this problem whith different code versions for .net 3.5, 4.0 and 4.5 frameworks that use different version of MongoDB driver (check MongoDB driver compatibility), wich has been very helpful.

Related

The provider for the source IQueryable doesn't implement IAsyncQueryProvider

I have some codes like below, I want to write unit tests my method. But I'm stuck in async methods. Can you help me please ?
public class Panel
{
public int Id { get; set; }
[Required] public double Latitude { get; set; }
public double Longitude { get; set; }
[Required] public string Serial { get; set; }
public string Brand { get; set; }
}
public class CrossSolarDbContext : DbContext
{
public CrossSolarDbContext()
{
}
public CrossSolarDbContext(DbContextOptions<CrossSolarDbContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
public interface IGenericRepository<T>
{
Task<T> GetAsync(string id);
IQueryable<T> Query();
Task InsertAsync(T entity);
Task UpdateAsync(T entity);
}
public abstract class GenericRepository<T> : IGenericRepository<T>
where T : class, new()
{
protected CrossSolarDbContext _dbContext { get; set; }
public async Task<T> GetAsync(string id)
{
return await _dbContext.FindAsync<T>(id);
}
public IQueryable<T> Query()
{
return _dbContext.Set<T>().AsQueryable();
}
public async Task InsertAsync(T entity)
{
_dbContext.Set<T>().Add(entity);
await _dbContext.SaveChangesAsync();
}
public async Task UpdateAsync(T entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
}
}
public interface IPanelRepository : IGenericRepository<Panel> { }
public class PanelRepository : GenericRepository<Panel>, IPanelRepository
{
public PanelRepository(CrossSolarDbContext dbContext)
{
_dbContext = dbContext;
}
}
[Route("[controller]")]
public class PanelController : Controller
{
private readonly IPanelRepository _panelRepository;
public PanelController(IPanelRepository panelRepository)
{
_panelRepository = panelRepository;
}
// GET panel/XXXX1111YYYY2222
[HttpGet("{panelId}")]
public async Task<IActionResult> Get([FromRoute] string panelId)
{
Panel panel = await _panelRepository.Query().FirstOrDefaultAsync(x => x.Serial.Equals(panelId, StringComparison.CurrentCultureIgnoreCase));
if (panel == null) return NotFound();
return Ok(panel);
}
}
public class PanelControllerTests
{
private readonly PanelController _panelController;
private static readonly Panel panel = new Panel { Id = 1, Brand = "Areva", Latitude = 12.345678, Longitude = 98.7655432, Serial = "AAAA1111BBBB2222" };
private readonly IQueryable<Panel> panels = new List<Panel>() { panel }.AsQueryable();
private readonly Mock<IPanelRepository> _panelRepositoryMock = new Mock<IPanelRepository>();
public PanelControllerTests()
{
_panelRepositoryMock.Setup(x => x.Query()).Returns(panels);
// I also tried this. I got another error 'Invalid setup on an extension method: x => x.FirstOrDefaultAsync<Panel>(It.IsAny<Expression<Func<Panel, Boolean>>>(), CancellationToken)'
// _panelRepositoryMock.As<IQueryable<Panel>>().Setup(x => x.FirstOrDefaultAsync(It.IsAny<Expression<Func<Panel, bool>>>(), default(CancellationToken))).ReturnsAsync(panel);
_panelController = new PanelController(_panelRepositoryMock.Object);
}
[Fact]
public async Task Register_ShouldInsertOneHourElectricity()
{
IActionResult result = await _panelController.Get("AAAA1111BBBB2222");
Assert.NotNull(result);
var createdResult = result as CreatedResult;
Assert.NotNull(createdResult);
Assert.Equal(201, createdResult.StatusCode);
}
}
I'm getting this error
The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.
I think that I need to mock 'FirstOrDefaultAsync' but I'm not sure and I don't know how to do. I tried something, however it couldn't be compiled.
I get stuck on this issue today and this lib resolve it for me https://github.com/romantitov/MockQueryable completely, please refer:
Mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc.
//1 - create a List<T> with test items
var users = new List<UserEntity>()
{
new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")},
...
};
//2 - build mock by extension
var mock = users.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);
//3 - setup the mock as Queryable for NSubstitute
_userRepository.GetQueryable().Returns(mock);
You could implement an AsyncEnumerable which can be used like this:
private readonly IQueryable<Panel> panels = new AsyncEnumerable(new List<Panel>()
{
panel
});
Here is the implementation of it:
public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
public AsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public AsyncEnumerable(Expression expression) : base(expression) { }
public IAsyncEnumerator<T> GetEnumerator()
{
return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IQueryProvider IQueryable.Provider => new AsyncQueryProvider<T>(this);
}
The AsyncEnumerator class:
public class AsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public T Current => _inner.Current;
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
}
The AsyncQueryProvider class:
public class AsyncQueryProvider<TEntity> : IAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal AsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new AsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new AsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
return new AsyncEnumerable<TResult>(expression);
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
This is because of your mocking approach; your mock provider just returns panels for Query, and panels is a simple object with LINQ-to-Objects exposing it as queryable:
private readonly IQueryable<Panel> panels = new List<Panel>() { panel }.AsQueryable();
Indeed, this does not implement IAsyncQueryProvider. If you can get hold of the regular query provider, you should be able to wrap that with a fake always-synchronous version to spoof it (just use return Task.FromResult(Execute(expression))), but frankly I'm not sure that this would be a useful test... at that point you're skipping so many of the important realities of async that it probably isn't worth it.
For issue in entity framework core ,use Moq.EntityFrameworkCore library and setup your dbset as below:
contextMock.Setup(x => x.entity).ReturnsDbSet(entityList);
I was facing the same issue and solved it that way:
Instead of having my method public async Task I switched it to public void and then resolved the asynchronous methods with .GetAwaiter() instead of await.
When querying for panel, removing the async in firstordefault.
Also remove the async from tolist when querying for analytics

How do I use GraphDiff when DBContext is abstracted?

I have just learned about GraphDiff, and how it is supposed to take care of all the differences between the disconnected entity and the one stored in the database.
The thing is that I do not know how to use GraphDiff, I tried the documentation, but I didn't understand it well.
I am using an abstracted DBContext, through an Interface and using DbSet so I could perform Unit Testing on them:
public interface IDbRepositories
{
IDbSet<Client> ClientsDB { get;}
AppIdentityDbContext DB { get; }
IDbSet<Contacts> ContactsDB { get; }
IDbSet<ExposureResult> ExposureDB { get; }
IDbSet<OrderMods> OrderModsDB { get; }
IDbSet<ProductDetails> ProductDetailsDB { get; }
IDbSet<OrderProcess> OrderProcessDB { get; }
IDbSet<Order> OrderDB { get; }
void SaveChanges();
}
This is the actual class implementing the interface:
public class DbRepositories : IDbRepositories
{
private AppIdentityDbContext db = new AppIdentityDbContext();
//Get DB Context. This is done this way, so a Mock can be injected when testing
public IDbSet<Client> ClientsDB
{
get { return db.Clients; }
}
public AppIdentityDbContext DB
{
get { return db; }
}
public IDbSet<Contacts> ContactsDB
{
get { return db.Contacts; }
}
public IDbSet<ExposureResult> ExposureDB
{
get { return db.ExposureTBL; }
}
public IDbSet<OrderMods> OrderModsDB
{
get { return db.OrderMods; }
}
public IDbSet<ProductDetails> ProductDetailsDB
{
get { return db.ProductDetailsTBL; }
}
public IDbSet<OrderProcess> OrderProcessDB
{
get { return db.OrderProcesses; }
}
public IDbSet<Order> OrderDB
{
get { return db.OrderTBL; }
}
public void SaveChanges()
{
this.db.SaveChanges();
}
}
Now, the problem part is in here:
public bool SaveOrderChanges(OrderProcess[] Order, int OrderID, int uid)
{
//2nd Step:
var ComparableObject = dbs.OrderProcessDB.Where(x => x.OrderID == OrderID).ToList();
var Objections = dbs.OrderDB.Where(x => x.OrderID == OrderID).FirstOrDefault();
dbs.DB.UpdateGraph(dbs.OrderDB, m => m.OwnedCollection());
dbs.SaveChanges();
return true;
}
I'd like to tell the differences between the Order parameter and the one I extract from OrderProcessDB. These are a One to Many Relationship.
I do not know how to use GraphDiff for this scenario. Any ideas?
You could just expose the base DbContext object in the interface, but that would violate basic principles of encapsulation. The challenge is that the UpdateGraph method is a static extension off of the concrete DbContext class. Here is my solution:
First the interface:
public interface IMyDbContext
{
...
TEntity UpdateGraph<TEntity>(TEntity entity, Expression<Func<IUpdateConfiguration<TEntity>, object>> mapping = null) where TEntity : class, new();
}
Then the actual DbContext:
public class MyDbContext : DbContext, IMyDbContext
{
...
public TEntity UpdateGraph<TEntity>(TEntity entity, Expression<Func<IUpdateConfiguration<TEntity>, object>> mapping = null) where TEntity : class, new()
{
return ((DbContext)this).UpdateGraph(entity, mapping);
}
}
And lastly example usage inside of a repository:
public class MyRepository : IMyRepository
{
private readonly IMyDbContext _myDbContext;
public MyRepository (IMyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task<SomeEntity> UpdateSomeEntity(SomeEntity updatedSomeEntity)
{
_myDbContext.UpdateGraph(updatedSomeEntity, map => map.OwnedCollection(p => p.SomeChildCollection));
await _myDbContext.SaveChangesAsync();
return updatedSomeEntity;
}
}
I realize this is old, but I just found out about GraphDiff and can hopefully help anyone else looking.
This is how you use GraphDiff:
db.UpdateGraph(orderToUpdate, map => map
.AssociatedCollection(t => t.Products)
.OwnedCollection(t => t.PaymentMethods));
This says to update the Order object, and that the Order owns the PaymentMethods (meaning it can actually remove those entities), and is associated with the Products entities (meaning it will remove them from the reference table).

C# database abstraction class with Entity Framework

I want to create a common database abstraction in order to expose the same interface without worrying about the type of the DbContext that the database manage.
Here there is an example in order to explain well the concept:
public interface IDatabase<T> where T : DbContext {
void Add<T>(T entity);
void Remove<T>(T entity);
void SaveChanges();
}
The implementation can be:
public MyDatabase<T> : IDatabase<T> where T : MyContext {
public T Context { get; private set; }
//singleton contructor ...
public void Add<TC>(TC entity) {
Context.Set<TC>().Add(entity);
}
public void Remove<TC>(TC entity) {
Context.Set<TC>().Add(entity);
}
public void SaveChanges {
Context.SaveChanges();
}
}
The goals of this design are different: expose the same interface in order to decouple logic from database, change quickly the database (context), create one time the context and reuse during all the application lifetime (lock mechanism are required).
The problem is that the interface hides all the types of the sets in the context.
Context.Set<TC>().Add(entity); //this line don't compile
I'm not sure that this design is the best practise. How can I implement a design that offers these features?
Why you does not use the standard pattern for example Repository pattern you can also combine it with UnitOfWork.
You make it complicated for your self, just check this.
public interface IMyClassRepository : IDisposable
{
IQueryable<MyClass> All { get; }
IQueryable<MyClass> AllIncluding(params Expression<Func<MyClass, object>>[] includeProperties);
MyClass Find(int id);
void InsertOrUpdate(MyClass myClass);
void Delete(int id);
void Save();
}
public class MyClassRepository : IMyClassRepository
{
DBContext context = new DBContext();
public IQueryable<MyClass> All
{
get { return context.Employees; }
}
public IQueryable<MyClass> AllIncluding(params Expression<Func<MyClass, object>>[] includeProperties)
{
IQueryable<MyClass> query = context.MyClasses;
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public MyClass Find(int id)
{
return context.MyClasses.Find(id);
}
public void InsertOrUpdate(MyClass myClass)
{
if (myClass.Id == default(int))
{
// New entity
context.MyClasses.Add(myClass);
}
else
{
// Existing entity
context.Entry(myClass).State = EntityState.Modified;
}
}
public void Delete(int id)
{
var employee = context.Employees.Find(id);
context.Employees.Remove(employee);
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public class MyClass
{
}

How to Implement Repository FindAll() Method?

I have the following Repository Pattern. Requirement is to “Find All accounts whose owner’s name is Lijo”. So, I need to write a FindAll function. How to write this function?
Constraints are:
1) The client “BankAccountService” should not use classes from 'DBML_Project'.
2) We should NOT use GetAll method to retireve complete list of accounts and then do a filter.
Note: I confronted this problem while working on the question Polymorphism: Is ORM entity a Domain Entity or Data Entity?
CODE
namespace ApplicationService_Bank
{
public class BankAccountService
{
RepositoryLayer.ILijosBankRepository accountRepository = new RepositoryLayer.LijosSimpleBankRepository();
public void FreezeAllAccountsForUser(string userName)
{
//Should not use assembly 'DBML_Project'.
IEnumerable<DomainEntitiesForBank.IBankAccount> accountsForUserWithNameLIJO = null;
//accountsForUserWithNameLIJO = accountRepository.FindAll(p => p.BankUser.Name == "Lijo");
}
}
}
namespace RepositoryLayer
{
public interface ILijosBankRepository
{
List<DomainEntitiesForBank.IBankAccount> GetAll();
IEnumerable<DBML_Project.BankAccount> FindAll(System.Func<DBML_Project.BankAccount, bool> predicate);
void SubmitChanges();
}
public class LijosSimpleBankRepository : ILijosBankRepository
{
private IBankAccountFactory bankFactory = new MySimpleBankAccountFactory();
public System.Data.Linq.DataContext Context
{
get;
set;
}
public virtual List<DomainEntitiesForBank.IBankAccount> GetAll()
{
List<DBML_Project.BankAccount> allItems = Context.GetTable<DBML_Project.BankAccount>().ToList();
List<DomainEntitiesForBank.IBankAccount> bankAccounts = new List<DomainEntitiesForBank.IBankAccount>();
foreach (DBML_Project.BankAccount acc in allItems)
{
DomainEntitiesForBank.IBankAccount theAccount = bankFactory.CreateAccount(acc.AccountType, acc.BankAccountID, acc.Status, acc.OpenedDate, acc.AccountOwnerID);
bankAccounts.Add(theAccount);
}
return bankAccounts;
}
public IEnumerable<DBML_Project.BankAccount> FindAll(System.Func<DBML_Project.BankAccount, bool> predicate)
{
//Where
var results = Context.GetTable<DBML_Project.BankAccount>().Where(predicate);
return results;
}
public virtual void SubmitChanges()
{
Context.SubmitChanges();
}
}
}
READING:
Returning IEnumerable<T> vs. IQueryable<T>
how to design Repository pattern to be easy switch to another ORM later?
A simple approach is to just build the query by hand:
public class SearchCriteria
{
public string Name { get; set; }
// ...more
}
public IEnumerable<Entity> FindAll(SearchCriteria criteria)
{
IQueryable<Entity> entities = _datasource.Entities; // replace with your L2S equivalent
if (criteria.Name != null)
entities = entities.Where(e => e.Name == criteria.Name);
// ...more
return entities;
}
If you don't want to return the generated objects directly, map to something else before you return:
return Map(entities); // IEnumerable<CustomObject> Map(IEnumerable<Entity> entities)

C# Unit testing with Fake database context using a HashSet (pluralsight code)(New Q)

The short version:
In this video, Mr. Scott Allen explains how to test a controller.
But he does not show the full code of the class: FakeDbContext.
Is there someone who can help me finish it? He shows the class at, 06:15 min in the video for "testing controllers".
The long version
At school I have a elective where we learn C#. My exam project is a ASP site using MVC3.
To learn it fast, i have seen videos from PluralSight. My question is about some code that are in this video
He explains how to test controllers. So i tried:
I have made a controller which has a simple index method:
public class Round1Controller : Controller
{
IDbContext _db;
public Round1Controller()
{
_db = new Entities();
}
public Round1Controller(IDbContext db)
{
_db = db;
}
public ActionResult Index()
{
var model = _db.ELECTIVES.ToList();
return View(model);
}
As you can see i have already tried to make a context.
The index method is the one i want to TEST.
The next thing he does is to make a class called, FakeDbContext, in the test project.
But sadly he only show a part of the code, and i have used a lot of hours trying to figure out how he creates a get method to a HashSet.
Here is the code that you can see from the video:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EESS.Models;
namespace EESS.Tests
{
class FakeDbContext : IDbContext
{
public IQueryable<Restaurant> Restaurants
{
get { return _map.Get<Restaurant>().asQueryable(); }
set { _map.Use<Restaurant>(value); }
}
public IQueryable<Review> Reviews
{
get { return _map.Get<Review>().asQueryable(); }
set { _map.Use<Review>(value); }
}
public int SaveChanges()
{
ChangesSaved = true;
return 0;
}
public bool ChangesSaved { get; set; }
public T Attach<T>(T entity) where T : class
{
_map.Get<T>().Add(entity);
return entity;
}
public T Add<T>(T entity) where T : class
{
_map.Get<T>().Add(entity);
return entity;
}
public T Delete<T>(T entity) where T : class
{
_map.Get<T>().Remove(entity);
return entity;
}
SetMap _map = new SetMap();
class SetMap : KeyedCollection<Type, object>
{
public HashSet<T> Use<T>(IEnumerable<T> sourceData)
{
var set = new HashSet<T>(sourceData);
if (Contains(typeof(T)))
{
Remove(typeof(T));
}
Add(set);
return set;
}
}
}
}
To end the long version, my problem is i get a error on _Map.Get.
Does not contain a definition or extension method.
EDIT! PART 2:
After #xelibrion great answer it finally worked.
But then another problem come up.
The IDbContext class looks like this:
public interface IDbContext
{
IQueryable<ELECTIVES> ELECTIVES { get; }
int SaveChanges();
T Attach<T>(T entity) where T : class;
T Add<T>(T entity) where T : class;
T Delete<T>(T entity) where T : class;
}
When i add this interface to my Entities Class it offcouse expect me to implement the methods.
PluralSight implements them like this:
public DbSet<ELECTIVES> electives { get; set; }
IQueryable<ELECTIVES> IDbContext.ELECTIVES
{
get { return electives; }
}
int IDbContext.SaveChanges()
{
return SaveChanges();
}
T IDbContext.Add<T>(T entity)
{
return Set<T>().Add(entity);
}
T IDbContext.Delete<T>(T entity)
{
return Set<T>().Remove(entity);
}
T IDbContext.Attach<T>(T entity)
{
var entry = Entry(entity);
entry.State = System.Data.EntityState.Modified;
return entity;
return Set<T>().Add(entity);
}
But my "_dbModel.Designer.cs" class from my entity model does not know what Set and Entry is, and only suggest i make a method stub. There are a lot more code in this class, so if its need just ask for the rest :) I have changed Restaurants to Electives since thats the table name i my DB.
Is it a "using" i have forgotten? I have seen the video again, and he does not have a method stub in his DB class.
I suppose full version of SetMap class should look like this
class SetMap : KeyedCollection<Type, object>
{
public HashSet<T> Use<T>(IEnumerable<T> sourceData)
{
var set = new HashSet<T>(sourceData);
if (Contains(typeof(T)))
{
Remove(typeof(T));
}
Add(set);
return set;
}
public HashSet<T> Get <T>()
{
return (HashSet<T>) this[typeof(T)];
}
protected override Type GetKeyForItem(object item)
{
return item.GetType().GetGenericArguments().Single();
}
}

Categories