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).
Related
I have the following classes (reduced for simplicity).
public class User : Entity
{
public List<Skill> Skills { get; set; }
}
public class Skill : ValueObject
{
public string Name { get; private set; }
}
My UserConfiguration class is the following:
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder
.OwnsMany(user => user.Skills);
}
}
Here I am saying EF that my User class owns some Skills and it generates the following table:
I use the Unit of Work pattern, so in my repository I do the following on my Update method:
public virtual void Update(T entityToUpdate)
{
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
And after updating I call my Commit method, which saves the changes:
public void Commit()
{
_dbContext.SaveChanges();
}
As far as I have been able to see, on getting the User entity I am receiving all the properties correctly (including the Skills), but on updating is updating each property but the Skills.
I have tried to manually set the Skill's table Primary Key and Foreign Key changing the UserConfiguration class this way (with the same result, skills are not updated):
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder
.OwnsMany(user => user.Skills, skill =>
{
skill.WithOwner().HasForeignKey("UserId");
skill.Property<int>("Id");
skill.HasKey("id");
});
}
}
I have also tried to change my Update method to:
public virtual void Update(T entityToUpdate)
{
_dbSet.Update(entityToUpdate);
}
But I am getting the following exception: Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException : Database operation expected to affect 1 row(s) but actually affected 0 row(s).
Note that Skill is a ValueObject (it has a shadow Id). I actually believe there should be the problem.
Thanks a lot for your help.
Edit: Since #pejman answer is not working for me I am going to put here my UnitOfWork, Repository and Context (reduced for simplicity), since are the only things I have not done like #pejman, maybe the problem is right there, but I am not able to see it.
Repository:
class BaseRepository<T> : IRepository<T> where T : Entity
{
private readonly Context _context;
private readonly DbSet<T> _dbSet;
public BaseRepository(Context context)
{
_context = context;
_dbSet = context.Set<T>();
}
public virtual T GetById(Guid id) => _dbSet.AsNoTracking().FirstOrDefault(x => x.Id == id);
public virtual void Update(T entityToUpdate)
{
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
Unit of work:
public class UnitOfWork : IUnitOfWork
{
private const int SqlObjectAlreadyExistsErrorNumber = 2627;
private readonly Context _dbContext;
private BaseRepository<User> _users;
public UnitOfWork(Context dbContext)
{
_dbContext = dbContext;
}
public IRepository<User> Users
{
get
{
return _users ??= new BaseRepository<User>(_dbContext);
}
}
public void Commit()
{
_dbContext.SaveChanges();
}
}
Context:
public class Context : DbContext
{
public Context(DbContextOptions<DeribeContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(DeribeContext).Assembly);
base.OnModelCreating(modelBuilder);
}
}
Updating collection navigation properties of disconnected entities has very limited support. First off, they are not considered part of the entity data. Second, it's not quite clear what should be done with the existing child entities not found in the disconnected entity.
All this is because EF Core has no information about the original database state, as in their primary supported (and the only reliable) flow of Load (in db context change tracker), Modify, Save.
In theory collections of owned entity types should be handled easier than collection of regular entities. Since they are considered part of the owner (at least when loading), they could have been processed as such during the update, i.e. replace by first deleting all exiting and then insert (add) all incoming.
In practice (current EF Core) updating them in disconnect scenario is virtually impossible. Not only they are not handled automatically, but since you can't define DbSet (hence use Set<T>() method) of owned entity type, there is no other way to tell EF Core to delete existing by actually loading them from the database and clearing the collection. This along with the fact that explicit/lazy loading does not work, leaves the only option of load the owner entity from database.
And once you do that, then better apply the modified properties as well (using CurrentValues.SetValues method), rather than using the "forced update" all which is happening when using Update method (or setting State to EntityState.Modified).
Apply it to your sample model would be something like this
var dbUser = _context.Set<User>().FirstOrDefault(e => e.Id == user.Id);
_context.Entry(dbUser).CurrentValues.SetValues(user);
dbUser.Skills = user.Skills;
Since the only custom code is dbUser.Skills = user.Skills;, it could be generalized for any collection of owned entity types by using EF Core provided metadata and change tracking API:
public virtual void Update(T entityToUpdate)
{
// Load existing entity from database into change tracker
var entity = _dbSet.AsTracking()
.FirstOrDefault(x => x.Id == entityToUpdate.Id);
if (entity is null)
throw new KeyNotFoundException();
var entry = _context.Entry(entity);
// Copy (replace) primitive properties
entry.CurrentValues.SetValues(entityToUpdate);
// Copy (replace) owned collections
var ownedCollections = entry.Collections
.Where(c => c.Metadata.TargetEntityType.IsOwned());
foreach (var collection in ownedCollections)
{
collection.CurrentValue = (IEnumerable)collection.Metadata
.GetGetter().GetClrValue(entityToUpdate);
}
}
Try this, it worked properly:
public class User : Entity
{
private List<Skill> _skills;
public IReadOnlyList<Skill> Skills => _skills.AsReadOnly();// use this way
//for more encapsulation
public void AssignSkills(List<Skill> skills)
{
this._skills = skills;
}
}
and Skill class :
public class Skill
{
public Skill(string name, string desc)
{
this.Name = name;
Description = desc;
}
protected Skill() { }
public string Name { get; private set; }
public string Description { get; private set; }
}
public class Entity
{
public int Id { get; set; }
}
for Mapping:
public class UserMapping : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.Property(a => a.Id).ValueGeneratedNever();
builder.OwnsMany(a => a.Skills, map =>
{
map.ToTable("Skills").HasKey("Id");
map.Property<int>("Id");
map.WithOwner().HasForeignKey("UserId");
map.UsePropertyAccessMode(PropertyAccessMode.Field);
});
}
}
and MyContext:
public class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=users;Integrated Security=true");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(UserMapping).Assembly);
base.OnModelCreating(modelBuilder);
}
}
and in last which i try to add a list of skills to user then update the list, and it worked properly:
static async Task Main(string[] args)
{
using (var dbContext = new MyDbContext())
{
var user = new User();
var skills = new List<Skill>()
{
new Skill("first skill","desc1"),
new Skill("sec skill","desc2"),
};
user.AssignSkills(skills);
dbContext.Users.Add(user);
dbContext.SaveChanges();
}
using (var readContext = new MyDbContext())
{
var user = readContext.Users.First();
var skills = new List<Skill>()
{
new Skill("first skill","desc1"),
new Skill("sec skill","desc_change"),
new Skill("third skill","desc_New"),
};
user.AssignSkills(skills);
await readContext.SaveChangesAsync();
}
I have one EF edmx(BaseEntities). As business requirement, I created two files called.
QTDAL and AdminDAL.
Please see the following codes. My two classes (QTDAL, AdminDAL) inheritances to BaseEntities. (Note: I am not sure this is allowed to do that)
(No errors now)
I would like to have suggestions if there is any better solution to achieve as the below code.
Any advise, please ?
public void TestMethod1()
{
IQTDAL qtContext = new QTDAL();
var value = qtContext.AllCampaigns().FirstOrDefault();
//var value = qtContext.AddOrUpdateCampaign(TestCampaign);
Assert.IsNotNull(value);
}
Examples:
public partial class BaseEntities : DbContext
{
public BaseEntities()
: base("name=BaseEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Campaign> Campaigns { get; set; }
public virtual DbSet<User> Users { get; set; }
}
public class QTDAL : BaseEntities, IQTDAL
{
public IEnumerable<Campaign> AllCampaigns()
{
return Campaigns.ToList();
}
public int AddOrUpdateCampaign(Campaign campaign)
{
Campaigns.AddOrUpdate(campaign);
return SaveChanges();
}
public int DeleteCampaign(Campaign campaign)
{
Campaigns.Remove(campaign);
return SaveChanges();
}
}
public class AdminDAL : BaseEntities, IAdminDAL
{
public IEnumerable<User> AllUsers()
{
return Users;
}
public int AddOrUpdateUser(User user)
{
Users.AddOrUpdate(user);
return SaveChanges();
}
public int DeleteUser(User user)
{
Users.Remove(user);
return SaveChanges();
}
}
Well, you certainly CAN inherit from your context, but the real question is why would you?
Inheritance is a concept that is used to create an "is a" relationship. In other words, your QTDAL "is a" BaseEntities. So you can treat a QTDAL as a BaseEntities object. You do not appear to be using it that way. Instead, you seem to be wanting to wrap the BaseEntities functionality.
In which case, you should simply be using BaseEntities as a member of your QTDAL class.
Is there some automated awesomeness that entity framework does that means I do not have to re-write the crud controllers and views to work with my repository and unity framework injection :( ?
It references the entityframework database context explicitly in the controllers... and then does actual data operations inside the controllers themselves...
for example, this ends up in my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="ProductID,Title")] Product product)
{
if (ModelState.IsValid)
{
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(product);
}
when really the .Add and .SaveChanges need to be in my repository...
I don't want to write the 50 CRUD operations or copy and paste views and controllers every time I want to create that stuff... Is there a way of automating
probably something like this:
namespace WebApplication.Domain.Abstract
{
public interface IProductRepository
{
IQueryable<Product> Products { get; }
Product Create(Product product);
... yada yada crud operations
}
}
public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products
{
get { return context.Products; }
}
//... implements all the CRUD operations that entity framework ends up placing inside the controller
}
Since according to comments this is what has solved the problem:
Visual Studio provides a built-in way for template based code generation. It's called T4 and you can read more about it here.
A generic Repository<TPoco> is the general approach here.
ie 1 Repository reused with for every POCO.
It is also commonly used with a Unit Of Work Pattern to combine updates into a logical unit of work.
Here is a basic Demo to illustrate the point.
BUT IDEALLY an IRepository is declared in a core Layer
and a Data Access layer implements Repositiry:IRepository to keep ef references
out of a core domain layer. (That is another important related code architecture matter to research)
This demo is too short for IRepository<t>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace repofT
{
class Program
{
static void Main(string[] args)
{
// Kick Start Repository of T demo
// There are advance models combining context creation / unit of work and repository.
// The concept of Inversion of Control / Dependency injection should be inestigated
// for the people new to IOC
// SIMPLIFIED Unit of Work and Respository of T sample
var ctx = new MyContext();
var uow = new UnitOfWork(ctx);
var rep = new Repository<MyPoco>(ctx);
addTest(rep, uow);
var poco1 = FindTest(rep);
ChangeTest(poco1, rep, uow);
Console.ReadKey();
}
private static void ChangeTest(MyPoco poco1, Repository<MyPoco> rep, UnitOfWork uow)
{
poco1.Content = "Test - was changed";
rep.Change(poco1);
uow.Commit();
DumpTest(rep);
}
private static MyPoco FindTest(Repository<MyPoco> rep)
{
var poco1 = rep.Find(1);
Console.WriteLine(poco1.Id + " : " + poco1.Content);
return poco1;
}
private static void addTest(Repository<MyPoco> rep, UnitOfWork uow)
{
var mypoco = new MyPoco()
{
Content = "Test" + System.DateTime.Now.ToString(CultureInfo.InvariantCulture),
};
rep.Add(mypoco);
uow.Commit();
DumpTest(rep);
}
private static void DumpTest(Repository<MyPoco> rep)
{
var pocoList = rep.GetList(t => t.Content.StartsWith("Test"));
if (pocoList != null)
{
foreach (var poco in pocoList)
{
Console.WriteLine(poco.Id + " : " + poco.Content);
}
}
}
}
}
And the repository/Unit of work and Context classes
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Data.Entity.Validation;
using System.Linq.Expressions;
namespace repofT
{
/// <summary>
/// Note to the reader. NO error handling. You should add your preferred solution.
/// This is a stripped down sample to illustrate how Repository of T pattern works.
/// </summary>
public class MyContext : DbContext
{
public DbSet<MyPoco> MyPocos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//fluent API....
base.OnModelCreating(modelBuilder);
var entity = modelBuilder.Entity<MyPoco>();
entity.HasKey(t => t.Id) ;
entity.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class MyPoco
{
//virtuals for EF, especially Proxies and navigation, Use public get/set
public virtual int Id { get; set; }
public virtual string Content { get; set; }
}
public class Repository<TPoco> where TPoco : class, new()
{
public DbContext Context { get; private set; }
public Repository(DbContext context){
Context = context;
}
public IList<TPoco> GetList(Expression<Func<TPoco, bool>> predicate)
{
// Investigate returning IQueryable versus IList as you learn more.
return GetQuery(predicate).ToList();
}
public IQueryable<TPoco> GetQuery(Expression<Func<TPoco, bool>> predicate)
{
// Investigate returning IQueryable versus IList as you learn more.
return Context.Set<TPoco>().Where(predicate);
}
public TPoco Get(Expression<Func<TPoco, bool>> predicate)
{
return Context.Set<TPoco>().FirstOrDefault(predicate);
}
public TPoco Find(params object[] keyValues)
{
return Context.Set<TPoco>().Find(keyValues);
}
public TPoco Attach(TPoco poco)
{
return Context.Set<TPoco>().Add(poco);
}
public TPoco Add(TPoco poco){
return Context.Set<TPoco>().Add(poco);
}
public TPoco AddOrUpdate(TPoco poco){
return Context.Set<TPoco>().Add(poco);
}
public TPoco Remote(TPoco poco){
return Context.Set<TPoco>().Remove(poco);
}
public void Change(TPoco poco){
Context.ChangeTracker.DetectChanges();
}
public void SetEntityState(TPoco poco, EntityState state = EntityState.Modified){
Context.Entry(poco).State = state;
}
}
public class UnitOfWork
{
public DbContext Context { get; protected set; }
public UnitOfWork(DbContext context){
Context = context;
}
public IEnumerable<DbEntityValidationResult> GetDbValidationErrors() { return
Context.GetValidationErrors();
}
public int Commit()
{
try {
var recs = Context.SaveChanges();
return recs;
}
catch (DbEntityValidationException efException){
var errors = GetDbValidationErrors(); // DO SOMETHING HERE !!!!!
return -1;
}
}
}
}
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)
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();
}
}