I'm using:
EF 6.2,
VisualStudio 2017,
nUnit 2.6.3.13283 (unit test),
Unity 5.8.5 (as IoC).
The problem appears when I want to test two different DbContexts in the same UnitTest.
First Context:
public class MsSqlConfiguration : System.Data.Entity.DbConfiguration
{
public MsSqlConfiguration()
{
this.SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
this.SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
}
}
[DbConfigurationType(typeof(MsSqlConfiguration))]
public class SqlDbContext: DbContext
{
public SqlDbContext(string connectonString) : base(connectonString)
{}
public DbSet<SomeClass> SomeField { get; set; }
}
Second context:
public class SQLiteProviderInvariantName : IProviderInvariantName
{
public static readonly SQLiteProviderInvariantName Instance = new SQLiteProviderInvariantName();
private SQLiteProviderInvariantName() { }
public const string ProviderName = "System.Data.SQLite.EF6";
public string Name { get { return ProviderName; } }
}
class SQLiteDbDependencyResolver : IDbDependencyResolver
{
public object GetService(Type type, object key)
{
if (type == typeof(IProviderInvariantName)) return SQLiteProviderInvariantName.Instance;
if (type == typeof(DbProviderFactory)) return SQLiteProviderFactory.Instance;
return SQLiteProviderFactory.Instance.GetService(type);
}
public IEnumerable<object> GetServices(Type type, object key)
{
var service = GetService(type, key);
if (service != null) yield return service;
}
}
public class SQLiteConfiguration : System.Data.Entity.DbConfiguration
{
public SQLiteConfiguration()
{
AddDependencyResolver(new SQLiteDbDependencyResolver());
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
}
}
[DbConfigurationType(typeof(SQLiteConfiguration))]
public class SqlDbContext : DbContext
{
public SqlDbContext (string connectonString) : base(connectonString)
{
}
public DbSet<SomeClass> SomeField{ get; set; }
}
UnitTest:
[TestFixture]
class DbContextIntegrationTests
{
[Test]
public void CanReadFromMsSqlDatabase()
{
using (var context = IocContainer.Instance.Resolve<MsSqlDbContext>(someConnString))
{
Assert.DoesNotThrow(() => context.SomeField.FirstOrDefault());
}
}
[Test]
public void CanReadFromSqliteDatabase()
{
using (var context2 = IocContainer.Instance.Resolve<SqliteDbContext>(someConnString2))
{
Assert.DoesNotThrow(() => context2.Somefield.FirstOrDefault());
}
}
}
When I instantiate the above context separately by passing connection string - they both works fine.
However if they are a part of the same unit test class - they can't be run.
First context set it's provider as default (let say SQL one) and the next one DbContext (say SQLite one) can't set it's provider.
If MS SQL dbcontext goes first, then SQLite dbcontext get next exception:
System.InvalidOperationException: 'Unable to complete operation. The
supplied SqlConnection does not specify an initial catalog or
AttachDBFileName.'
If SQLite goes first, then MS SQL context gets:
System.InvalidOperationException: 'The store type 'date' could not be found in the SQLite provider manifest'
I'm just wondering what I'm missing here.
Whether it's nUnit specific (some cache).
Or it's indeed some common place for EF providers which can be set only once.
I'm not using App.config at all - just passing config string from some saved place.
#Bit #programtreasures
Found the answer.
The root cause was in inability of EF to handle multiple DBConfiguration at the same time (probably in memory) even if they are parts of different DbContexts.
More details here:
https://msdn.microsoft.com/en-us/data/jj680699
So I've just created a common context:
using System.Data.Entity.Core.Common;
using System.Data.SQLite;
using System.Data.SQLite.EF6;
namespace ClassLibrary1
{
public class commonConfig : System.Data.Entity.DbConfiguration
{
public commonConfig()
{
SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
}
}
}
And MS SQL DB context:
using System.Data.Entity;
using System.Data.SqlClient;
namespace ClassLibrary1
{
[DbConfigurationType(typeof(commonConfig))]
public class MsSqlDbContext : DbContext
{
public MsSqlDbContext(SqlConnection existingConnection,
bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
{
DbConfiguration.SetConfiguration(new commonConfig());
}
public DbSet<SomeTableEntity> SomeTable { get; set; }
}
}
And SqliteDbContext:
using System.Data.Entity;
using System.Data.SQLite;
namespace ClassLibrary1
{
[DbConfigurationType(typeof(commonConfig))]
public class SqliteDbContext : DbContext
{
public SqliteDbContext(SQLiteConnection existingConnection,
bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
{
DbConfiguration.SetConfiguration(new commonConfig());
}
public DbSet<SomeDbTableEntity> SomeTable { get; set; }
}
}
Then I can run unit test like the below:
[TestMethod]
public void TestMethod()
{
using (var context1 = new SqliteDbContext(new SQLiteConnection(
#"C:\db.sqlite"), true
))
{
Console.WriteLine("SQLITE" + Environment.NewLine);
Console.Write(context1.SomeTable.FirstOrDefault().SomeRecord);
Console.WriteLine(Environment.NewLine);
}
using (var context2 =
new MsSqlDbContext(
new SqlConnection(#"Data Source=localhost;Initial Catalog=SomeDatabase;Integrated Security=True")
, true)
)
{
Console.WriteLine("MS SQL" + Environment.NewLine);
Console.Write(context2.SomeTable.FirstOrDefault().SomeRecord);
Console.WriteLine(Environment.NewLine);
}
}
Related
So I have been at it for days, and for the life of me cannot find any documentation that fits my situation exactly here.
I have essentially set up a custom navigation service and would like to call the command from my ViewModel Class directly from my User Control.
I think I'm on the edge of having it here, but my lack of experience with C# is shooting me in the foot.
Here is the section of code from my Login.xaml.cs in question:
private LoginViewModel _loginViewModel;
public Login(LoginViewModel loginViewModel)
{
_loginViewModel = loginViewModel;
}
private void GrantAccess()
{
int userAccess = Int16.Parse(User.Access);
if (userAccess == 1)
{
MessageBox.Show("The bottom man");
}
if (userAccess == 2)
{
MessageBox.Show("The little boss");
}
if (userAccess == 3)
{
MessageBox.Show("The little big boss");
}
if (userAccess == 4)
{
{
_loginViewModel.NavigateMM1Command.Execute(null);
}
}
}
and here is the command I'm trying to reference from the ViewModel:
public class LoginViewModel : BaseViewModel
{
public ICommand NavigateMM1Command { get; }
public LoginViewModel(NavigationStore navigationStore)
{
NavigateMM1Command = new NavigateCommand<MM1ViewModel>(new NavigationService<MM1ViewModel>(navigationStore, () => new MM1ViewModel(navigationStore)));
}
}
Basically I've been going through tutorial after tutorial trying to apply what they teach to what I need and its worked for the most part but now _loginViewModel is throwing a null reference exception and I'm not sure why.
I have tried:
LoginViewModel loginViewModel = new loginViewModel();
but its asking me to pass a navigationStore argument through it and that feels wrong.
Any help here will cure my temporary insanity XD
You're receiving a Null Object Reference because navigationStore is null when LoginViewModel is being constructed.
That is, you have not configured a means to instantiate the type navigationStore when constructing LoginViewModel.
Dependency Injection (DI), or Invocation of Control (IoC) is bit more comprehensive a subject to cover in this answer.
Having said that,
I'll provide code to review here. It represents a means to configure a service provider using a collection of type mappings.
In this complete, ConsoleApp example, we'll explicitly instantiate a ServiceCollection, add Service Types (specifying mapping where application), and Build the ServiceProvider; With that provider, we'll resolve and instantiate Login type using GetService -- instantiating all the types;
The Types are essentially mockups of the types you've specified, but I've modified some aspects (an made up notioned like what your Execute method and usage of NavigationStore was).
DemoNavTypes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleDemo.NavLoginDemo
{
public interface ICommand
{
void Execute(string? userName);
}
public interface INavigationStore {
public bool this[string index] { get;set; }
}
public interface INavigationService {
void GrantAccessToUser(string userName);
}
public interface INavigationViewModel { }
internal class NavigationStore : INavigationStore
{
private Dictionary<string, bool> userAccessDict;
public NavigationStore() {
userAccessDict = new Dictionary<string, bool>();
}
public bool this[string index] {
get => userAccessDict.TryGetValue(index, out var val) && val;
set => userAccessDict[index] = value;
}
}
internal class NavigationService : INavigationService
{
private readonly INavigationStore _navigationStore;
public NavigationService(INavigationStore navigationStore)
{
_navigationStore = navigationStore;
}
public void GrantAccessToUser(string? userName)
{
if (string.IsNullOrWhiteSpace(userName))
throw new ArgumentException(nameof(userName));
_navigationStore[userName!] = true;
}
}
internal class NavigationCommand : ICommand
{
private readonly INavigationService _navigationService;
public NavigationCommand(INavigationService navigationService)
{
_navigationService = navigationService;
}
public void Execute(string? userName)
{
if (userName != null)
{
_navigationService.GrantAccessToUser(userName);
}
}
}
internal class User
{
public string? Name { get; set; }
public string Access { get; set; } = "1";
}
public abstract class BaseViewModel
{
internal User User { get; set; } = new User();
protected BaseViewModel() { }
}
internal class LoginViewModel : BaseViewModel, INavigationViewModel
{
private readonly ICommand _command;
public LoginViewModel(ICommand command) : base()
{
_command = command;
}
internal ICommand NavigateMM1Command => _command;
}
internal class Login
{
private User User => _loginViewModel.User;
private readonly LoginViewModel _loginViewModel;
public Login(LoginViewModel loginViewModel)
{
_loginViewModel = loginViewModel;
}
internal void SetAccess(int access)
{
SetAccess($"{access}");
}
internal void SetAccess(string access)
{
User.Access = access;
}
internal void SetUserName(string userName) { User.Name = userName; }
internal async Task GrantAccessAsync()
{
await Task.Yield();
int userAccess = Int16.Parse(User.Access);
switch (userAccess)
{
case 1:
Console.WriteLine("The bottom man");
break;
case 2:
Console.WriteLine("The little boss");
break;
case 3:
Console.WriteLine("The little big boss");
break;
case 4:
_loginViewModel.NavigateMM1Command.Execute(User.Name);
break;
default:
throw new NotImplementedException();
}
}
}
}
Program.cs (using Microsoft.Extensions.DependencyInjection)
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Immutable;
using System.ComponentModel.Design;
using System.Linq;
using ConsoleDemo.NavLoginDemo;
internal class Program
{
private static async Task Main(string[] args)
{
var services = new ServiceCollection();
var provder = ConfigureServices(services);
var login = provder.GetService<Login>();
if (login != null)
{
await login.GrantAccessAsync();
login.SetAccess(2);
await login.GrantAccessAsync();
login.SetAccess(3);
await login.GrantAccessAsync();
login.SetUserName("James Bond");
login.SetAccess(4);
await login.GrantAccessAsync();
}
}
private static IServiceProvider ConfigureServices(IServiceCollection services)
{
return services
.AddScoped<INavigationStore, NavigationStore>()
.AddScoped<INavigationService, NavigationService>()
.AddScoped<ICommand, NavigationCommand>()
.AddScoped<LoginViewModel>()
.AddScoped<Login>()
.BuildServiceProvider();
}
}
Note
-- However,
In your application, you'll probably already have a ServiceCollection instance in your Program.cs or Startup.cs file. And the ServiceProvider (or HostProvider) will be managed over by the application; So, you probably won't need to explicitly resolve (or GetService<T>) -- just add the Service Type (mappings) in ServiceCollection. Those parameter types will be instantiated and 'injected' into the constructor of Type that is itself being instantiated.
I am trying to get example 2 of how to use policies in StructureMap working. I have created a small test-project (code below). Unfortunately for some reason there seem to be some dependency issues, since the .As<type> and .Each are both not working.
For the lines using As such as
user.Green.As<Database>().ConnectionString.ShouldBe("*green*");
I am getting the error:
'IDatabase' does not contain a definition for 'As' and no extension method 'As' accepting a first argument of type 'IDatabase' could be found (are you missing a using directive or assembly reference?). And for this line:
instance.Constructor.GetParameters()
.Where(x => x.ParameterType == typeof(IDatabase))
.Each(param => ...
'StringExtensions.Each(IEnumerable, Action)' is inaccessible due to its protection level.
I installed StructureMap 4.2 using NuGet. As you can see in the code below, I put in all the using-statements from StructureMap, that I could find, but I am still having the problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StructureMap;
using StructureMap.Pipeline;
using StructureMap.Pipeline.Lazy;
using StructureMap.Configuration;
using StructureMap.Building;
using StructureMap.Attributes;
using StructureMap.AutoMocking;
using StructureMap.Graph;
using StructureMap.Query;
using StructureMap.TypeRules;
using StructureMap.Util;
using StructureMap.Building.Interception;
using StructureMap.Configuration.DSL;
using StructureMap.Diagnostics.TreeView;
using StructureMap.Graph.Scanning;
namespace TestStructureMapPolicies
{
class Program
{
static void Main(string[] args)
{
var container = new Container(_ =>
{
_.For<IDatabase>().Add<Database>().Named("red")
.Ctor<string>("connectionString").Is("*red*");
_.For<IDatabase>().Add<Database>().Named("green")
.Ctor<string>("connectionString").Is("*green*");
_.Policies.Add<InjectDatabaseByName>();
});
// ImportantService should get the "red" database
container.GetInstance<ImportantService>()
.DB.As<Database>().ConnectionString.ShouldBe("*red*");
// BigService should get the "green" database
container.GetInstance<BigService>()
.DB.As<Database>().ConnectionString.ShouldBe("*green*");
// DoubleDatabaseUser gets both
var user = container.GetInstance<DoubleDatabaseUser>();
user.Green.As<Database>().ConnectionString.ShouldBe("*green*");
user.Red.As<Database>().ConnectionString.ShouldBe("*red*");
}
}
public interface IDatabase { }
public class Database : IDatabase
{
public string ConnectionString { get; set; }
public Database(string connectionString)
{
ConnectionString = connectionString;
}
public override string ToString()
{
return string.Format("ConnectionString: {0}", ConnectionString);
}
}
public class InjectDatabaseByName : ConfiguredInstancePolicy
{
protected override void apply(Type pluginType, IConfiguredInstance instance)
{
instance.Constructor.GetParameters()
.Where(x => x.ParameterType == typeof(IDatabase))
.Each(param =>
{
// Using ReferencedInstance here tells StructureMap
// to "use the IDatabase by this name"
var db = new ReferencedInstance(param.Name);
instance.Dependencies.AddForConstructorParameter(param, db);
});
}
}
public class BigService
{
public BigService(IDatabase green)
{
DB = green;
}
public IDatabase DB { get; set; }
}
public class ImportantService
{
public ImportantService(IDatabase red)
{
DB = red;
}
public IDatabase DB { get; set; }
}
public class DoubleDatabaseUser
{
public DoubleDatabaseUser(IDatabase red, IDatabase green)
{
Red = red;
Green = green;
}
// Watch out for potential conflicts between setters
// and ctor params. The easiest thing is to just make
// setters private
public IDatabase Green { get; private set; }
public IDatabase Red { get; private set; }
}
}
The As<T>() extension method I used in the tests isn't part of the BCL and that's why you're not finding it. If you're using Shouldly, you could effect the same thing with ShouldBeOfType<T>() or just cast it normally before making the comparisons. Same thing with the Each() extension.
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;
}
}
}
}
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();
}
}
I have a website and want to step over from MySql to SqlServer.
In my website I use a BE layer (Business Entities), BLL (Business Logic Layer), DAL (Data Access Layer), and of course a Web Layer (Website)
I've created a switch in the web.config (app settings) to tell the website to use MySql or SqlServer as DataProvider.
I use the folowing code.... which works perfectly, but my question is ...
Is this the right way to use a multi DAL tier?
Is this thread Safe ? or I have to implement Singleton at the Factory class ?
Please let me know what you should do, or what your opionion is.
namespace MyNameSpace.BE {
public class Product {
public int Id { get; set; }
public int Description { get; set; }
}
}
namespace MyNameSpace.DAL.Base {
public abstract class ProductManager {
public abstract List<Product> GetProductList();
}
}
namespace MyNameSpace.DAL.MySql {
public class ProductManager : Base.ProductManager {
public override List<Product> GetProductList() {
return new List<Product>();
}
}
}
namespace MyNameSpace.DAL.SqlServer {
public class ProductManager : Base.ProductManager {
public override List<Product> GetProductList() {
return new List<Product>();
}
}
}
namespace MyNameSpace.Bll {
/// do I have to use Singleton here ?? or not ?
public static class Factory {
private static ProductManager CreateProductManager() {
if (Config.Settings.Switches.DataProvider == DataProvider.MySql) {
return new DAL.MySql.ProductManager();
} else if (Config.Settings.Switches.DataProvider ==
DataProvider.SqlServer) {
return new DAL.SqlServer.ProductManager();
}
return null;
}
private static ProductManager _ProductManager;
public static ProductManager ProductManager {
get {
if (_ProductManager == null) {
_ProductManager = CreateProductManager();
}
return _ProductManager;
}
}
}
}
/// <summary>
/// for example ASP.NET page
/// </summary>
class MyPage {
public MyPage() {
List<Product> productList = Factory.ProductManager.GetProductList();
}
}
I recommend that you use an Inversion of Control (IoC) container. One such IoC container can be found in Microsoft Unity.