In relation of this answer, I'm trying to get multiple context to work by setting UseInMemoryDatabase to the same name. The test below fails, and the secondContext is empty.
What else do I need to do to share the same in memory database?
[Test]
public void MultipleContextTest()
{
var firstContext = new FirstContext(new DbContextOptionsBuilder<FirstContext>().UseInMemoryDatabase("DB").Options);
firstContext.Add(new Entity() {Name = "Test"});
firstContext.SaveChanges();
var secondContext = new SecondContext(new DbContextOptionsBuilder<SecondContext>().UseInMemoryDatabase("DB").Options);
Assert.AreEqual(1, secondContext.Entity.Count());
}
public class FirstContext : DbContext
{
public DbSet<Entity> Entity { get; set; }
public FirstContext(DbContextOptions options) : base(options)
{
}
}
public class SecondContext : DbContext
{
public DbSet<Entity> Entity { get; set; }
public SecondContext(DbContextOptions options) : base(options)
{
}
}
public class Entity
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
I got it working by setting the InMemoryDatabaseRoot to the same object on all contexts.
private InMemoryDatabaseRoot _root;
private InMemoryDatabaseRoot Root
{
get
{
if(_root == null)
_root = new InMemoryDatabaseRoot();
return _root;
}
}
[Test]
public void MultipleContextTest()
{
var firstContext = new FirstContext(CreateOptions<FirstContext>());
firstContext.Add(new Entity() {Name = "Test"});
firstContext.SaveChanges();
var secondContext = new SecondContext(CreateOptions<SecondContext>());
Assert.AreEqual(firstContext.Entity.Count(), secondContext.Entity.Count());
}
private DbContextOptions CreateOptions<T>() where T : DbContext
{
return new DbContextOptionsBuilder<T>()
.UseInMemoryDatabase("DB", Root)
.Options;
}
Related
I have 3 classes as you can see :
public class car
{
public int Id { set; get; }
public string Name { set; get; }
public List<CarTest> CarTest { get; set; }
public car(string name, int id, List<CarTest> carTests)
{
Id = id;
Name = name;
CarTest = carTests;
}
public car()
{
}
}
public class CarTest
{
public OVTest OV { get; set; }
public string CarOV { get; set; }
}
public class OVTest
{
public string Name { get; set; }
}
I want to edit my value as you can see :
static void Main(string[] args)
{
myctx myc = new myctx();
var cartests = new List<CarTest>();
var cartest = new CarTest();
var OV = new OVTest();
OV.Name = "editedName";
cartest.OV = OV;
cartest.CarOV = "2OV";
cartests.Add(cartest);
var editcar = new car("ee5155fe",2, cartests);
myc.ChangeTracker.TrackGraph(editcar, e =>e.Entry.State = EntityState.Modified);
myc.SaveChanges();
Console.ReadLine();
}
But I get this error :
System.InvalidOperationException: 'The property 'CarTestId' on entity type 'OVTest' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal.'
This is my config:
public class CarConfig : IEntityTypeConfiguration<car>
{
public void Configure(EntityTypeBuilder<car> builder)
{
builder.OwnsMany(u => u.CarTest);
builder.OwnsMany(u => u.CarTest).OwnsOne(c=>c.OV);
}
}
I am in need of some help Mocking and testing my class. I have tried various methods and feel this is the closest I have came. //1 and //2 are two separate attempts.
There is no error on method one but I do not know how to actually test anything with it using the Assert call.
Attempt 2 has the error message
Can not instantiate proxy of class: RentalsRated.Data.RentalsDBContext.
Test
[Fact]
public void RepoUA_GetAll()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring1", Username = "username1"},
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockContext = new Mock<RentalsDBContext>();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object).Verifiable();
//1
Mock<IRentalsRepository<UserAccount>> MockRepo = new Mock<IRentalsRepository<UserAccount>>();
MockRepo.Setup(m => m.GetAll()).Returns(users);
//2
var testClass = new RentalsRepository<UserAccount>(mockContext.Object);
var result = testClass.Get("idstring2");
Assert.Equal("idstring2", result.Id);
}
Repo
public class RentalsRepository<T> : IRentalsRepository<T> where T : BaseClass
{
private readonly RentalsDBContext _Context;
private DbSet<T> entities;
string errorMessage = string.Empty;
public RentalsRepository(RentalsDBContext _Context)
{
this._Context = _Context;
entities = _Context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return entities.AsEnumerable();
}
}
Context
public class RentalsDBContext : DbContext
{
public RentalsDBContext(DbContextOptions<RentalsDBContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
public virtual DbSet<UserAccount> UserAccounts { get; set; }
public virtual DbSet<Rating> Ratings { get; set; }
public virtual DbSet<PropertyAddress> PropertyAddresses { get; set; }
public virtual DbSet<Town> Towns { get; set; }
public virtual DbSet<County> Countys { get; set; }
public virtual DbSet<RatingImage> RatingImages { get; set; }
}
You are going to be a default constructor for the RentalsDBContext as Moq is unable to instantiate the class with its current constructor.
public class RentalsDBContext : DbContext {
public RentalsDBContext() : base() { }
public RentalsDBContext(DbContextOptions<RentalsDBContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
//...other code removed for brevity
}
Having the following context:
public class DemoContext : DbContext
{
private readonly string _connectionStringName = "DemoContext";
public DemoContext() : base("name=DemoContext")
{
//_connectionStringName = "DemoContext";
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
//Database.SetInitializer(new MigrateDatabaseToLatestVersion<DemoContext, Migrations.Configuration>(_connectionStringName));
Database.SetInitializer(new NullDatabaseInitializer<DemoContext>());
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Company> Companies { get; set; }
}
public class Employee
{
[Key]
public int EmployeeId { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class Company
{
[Key]
public int CompanyId { get; set; }
public string CompanyName { get; set; }
}
And this services:
public class EmployeeSvc
{
private readonly DemoContext _context;
public EmployeeSvc(Func<DemoContext> context)
{
_context = context();
}
public void Add(EmployeeAgg employee)
{
_context.Employees.Attach(new Employee()
{
Name = employee.Name,
DateOfBirth = employee.DateOfBirth
});
}
public void UpdateAll()
{
var employees = _context.Employees.ToList();
foreach (var employee in employees)
{
employee.Name = $"{Guid.NewGuid()}";
}
}
}
public class CompanySvc
{
private readonly DemoContext _context;
public CompanySvc(Func<DemoContext> context)
{
_context = context();
}
public void Add(CompanyAgg company)
{
_context.Companies.Attach(new Company()
{
CompanyName = company.CompanyName
});
}
public void UpdateAll()
{
var empresas = _context.Companies.ToList();
foreach (var empresa in empresas)
{
empresa.CompanyName = $"{Guid.NewGuid()}";
}
}
}
public class EmployeeAgg
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class CompanyAgg
{
public string CompanyName { get; set; }
}
Anf the following client code:
static void Main(string[] args)
{
var context = new DemoContext();
// ReSharper disable AccessToDisposedClosure
var employeeSvc = new EmployeeSvc(() => context);
var companySvc = new CompanySvc(() => context);
// ReSharper restore AccessToDisposedClosure
Console.WriteLine("Adding entities to context inside services");
employeeSvc.Add(new EmployeeAgg()
{
DateOfBirth = DateTime.Now.AddYears(-10),
Name = $"Employee name"
});
companySvc.Add(new CompanyAgg()
{
CompanyName = $"Company name"
});
employeeSvc.UpdateAll();
companySvc.UpdateAll();
context.SaveChanges();
context.Dispose();
Console.ReadLine();
}
Is it a good practice passing DbContext to application services as delegate in order to have a reference to a single instance and track all changes on it?
Maybe it's your example code, but there's no need here to use a delegate. You could as well just accept a DbContext and pass in the same instance:
public class EmployeeSvc
{
private readonly DemoContext _context;
public EmployeeSvc(DemoContext context)
{
_context = context();
}
// snip ...
}
public class CompanySvc
{
private readonly DemoContext _context;
public CompanySvc(DemoContext context)
{
_context = context();
}
// snip ...
}
var context = new DemoContext();
var employeeSvc = new EmployeeSvc(context);
var companySvc = new CompanySvc(context);
This would give you the exact same result, without needing to pass in a delegate and immediately invoking it.
I suppose however that maybe your actual code is a bit more complicated. If so, you should look into dependency injection and a DI-container.
A DI-container allows you to manage your dependencies and their lifecycles. A common lifecycle is the Singleton lifecycle, where the container will always construct your dependencies passing in the same instance.
if you need to injection your dbContext is better to use interface.
func<> is not suitable.
in Dependency injection interface is suitable.
(excusme for bad english)
I'm working on a project where I have some recursive data structure and I want to create a fixture for it.
The data structure is XmlCommandElement, it has a single method ToCommand that converts XmlCommandElement to Command.
Each node on the tree can be a XmlCommandElement and/or XmlCommandPropertyElement.
Now, in order to test the behaviour of the method ToCommand I want to fetch XmlCommandElement with some arbitrary data.
I want to control the depth of the tree and the amount of instances of XmlCommandElement and/or XmlCommandPropertyElement per node.
So here is the code I'm using for the fixture:
public class XmlCommandElementFixture : ICustomization
{
private static readonly Fixture _fixture = new Fixture();
private XmlCommandElement _xmlCommandElement;
public int MaxCommandsPerDepth { get; set; }
public int MaxDepth { get; set; }
public int MaxPropertiesPerCommand { get; set; }
public XmlCommandElementFixture BuildCommandTree()
{
_xmlCommandElement = new XmlCommandElement();
var tree = new Stack<XmlCommandElementNode>();
tree.Push(new XmlCommandElementNode(0, _xmlCommandElement));
while (tree.Count > 0) {
var node = tree.Pop();
node.Command.Key = CreateRandomString();
node.Command.Properties = CreateProperties();
if (MaxDepth > node.Depth) {
var commands = new List<XmlCommandElement>();
for (var i = 0; i < MaxCommandsPerDepth; i++) {
var command = new XmlCommandElement();
tree.Push(new XmlCommandElementNode(node.Depth + 1, command));
commands.Add(command);
}
node.Command.Commands = commands.ToArray();
}
}
return this;
}
public void Customize(IFixture fixture)
{
fixture.Customize<XmlCommandElement>(c => c.FromFactory(() => _xmlCommandElement)
.OmitAutoProperties());
}
private static string CreateRandomString()
{
return _fixture.Create<Generator<string>>().First();
}
private XmlCommandPropertyElement[] CreateProperties()
{
var properties = new List<XmlCommandPropertyElement>();
for (var i = 0; i < MaxPropertiesPerCommand; i++) {
properties.Add(new XmlCommandPropertyElement {
Key = CreateRandomString(),
Value = CreateRandomString()
});
}
return properties.ToArray();
}
private struct XmlCommandElementNode
{
public XmlCommandElementNode(int depth, XmlCommandElement xmlCommandElement)
{
Depth = depth;
Command = xmlCommandElement;
}
public XmlCommandElement Command { get; }
public int Depth { get; }
}
}
And this is how I'm using it:
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
This works perfectly fine! but the issue I have with it is it isn't generic, the whole point of AutoFixture at least as far as I know is to avoid making specific fixtures.
So what I would really like to do is something like this (found it here but it doesn't work for me.):
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthThrowingRecursionBehavior(2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandElement), 3));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandPropertyElement), 4));
xmlCommandElement = fixture.Create<XmlCommandElement>();
Here is all the code for reference:
Interfaces:
public interface ICommandCollection : IEnumerable<ICommand>
{
ICommand this[string commandName] { get; }
void Add(ICommand command);
}
public interface ICommandPropertyCollection : IEnumerable<ICommandProperty>
{
string this[string key] { get; }
void Add(ICommandProperty property);
}
public interface ICommandProperty
{
string Key { get; }
string Value { get; }
}
public interface ICommand
{
ICommandCollection Children { get; set; }
string Key { get; }
ICommandPropertyCollection Properties { get; }
}
public interface ICommandConvertible
{
ICommand ToCommand();
}
Classes:
public sealed class CommandPropertyCollection : ICommandPropertyCollection
{
private readonly IDictionary<string, ICommandProperty> _properties;
public CommandPropertyCollection()
{
_properties = new ConcurrentDictionary<string, ICommandProperty>();
}
public string this[string key]
{
get
{
ICommandProperty property = null;
_properties.TryGetValue(key, out property);
return property.Value;
}
}
public void Add(ICommandProperty property)
{
_properties.Add(property.Key, property);
}
public IEnumerator<ICommandProperty> GetEnumerator()
{
return _properties.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public sealed class CommandProperty : ICommandProperty
{
public CommandProperty(string key, string value)
{
Key = key;
Value = value;
}
public string Key { get; }
public string Value { get; }
}
public sealed class Command : ICommand
{
public Command(string key, ICommandPropertyCollection properties)
{
Key = key;
Properties = properties;
}
public ICommandCollection Children { get; set; }
public string Key { get; }
public ICommandPropertyCollection Properties { get; }
}
public class XmlCommandPropertyElement : ICommandPropertyConvertible
{
[XmlAttribute("key")]
public string Key { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
public ICommandProperty ToCommandProperty()
{
return new CommandProperty(Key, Value);
}
}
Finally, the class I'm trying to test is as follow:
public class XmlCommandElement : ICommandConvertible
{
[XmlArray]
[XmlArrayItem("Command", typeof(XmlCommandElement))]
public XmlCommandElement[] Commands { get; set; }
[XmlAttribute("key")]
public string Key { get; set; }
[XmlArray]
[XmlArrayItem("Property", typeof(XmlCommandPropertyElement))]
public XmlCommandPropertyElement[] Properties { get; set; }
public ICommand ToCommand()
{
ICommandPropertyCollection properties = new CommandPropertyCollection();
foreach (var property in Properties) {
properties.Add(property.ToCommandProperty());
}
ICommand command = new Command(Key, properties);
return command;
}
}
The test itself looks like this:
namespace Yalla.Tests.Commands
{
using Fixtures;
using FluentAssertions;
using Ploeh.AutoFixture;
using Xbehave;
using Yalla.Commands;
using Yalla.Commands.Xml;
public class XmlCommandElementTests
{
[Scenario]
public void ConvertToCommand(XmlCommandElement xmlCommandElement, ICommand command)
{
$"Given an {nameof(XmlCommandElement)}"
.x(() =>
{
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
});
$"When the object is converted into {nameof(ICommand)}"
.x(() => command = xmlCommandElement.ToCommand());
"Then we need to have a root object with a key"
.x(() => command.Key.Should().NotBeNullOrEmpty());
"And 4 properties as its children"
.x(() => command.Properties.Should().HaveCount(4));
}
}
}
Thanks to Mark Seemann! the final solution looks like this:
public class RecursiveCustomization : ICustomization
{
public int MaxDepth { get; set; }
public int MaxElements { get; set; }
public void Customize(IFixture fixture)
{
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(MaxDepth));
fixture.RepeatCount = MaxElements;
}
}
And can be used like this:
xmlCommandElement = new Fixture().Customize(new RecursiveCustomization {
MaxDepth = 2,
MaxElements = 3
}).Create<XmlCommandElement>();
You can fairly easily create a small tree by changing the Fixture's recursion behaviour:
[Fact]
public void CreateSmallTree()
{
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(recursionDepth: 2));
var xce = fixture.Create<XmlCommandElement>();
Assert.NotEmpty(xce.Commands);
}
The above test passes.
I'm working on a project that consists of multiple objects that I want to save to my database. I'm using a single context and a series of repository classes to access them.
When I try to save an entity, it seems to save all the virtual entities associated with it, even if that entity exists in the database already.
These are my classes:
public class Requirement
{
public int ID { get; set; }
public DateTime DateDue { get; set; }
public DateTime DateCompleted { get; set; }
public virtual Standard Standard { get; set; }
public virtual Project Project { get; set; }
}
public class Standard
{
public int ID { get; set; }
public int AgencyID { get; set; }
public string Name { get; set; }
public virtual Agency Agency { get; set; }
}
public class Project
{
public int ID { get; set; }
public bool Active { get; set; }
public virtual Agency Agency { get; set; }
public virtual Department Department { get; set; }
}
And this is the method I have for creating some data:
public class RequirementRepository
{
public static string CreateMockData()
{
StandardRepository stdRep = new StandardRepository();
ProjectRepository projRep = new ProjectRepository();
RequirementRepository reqRep = new RequirementRepository();
Project project = projRep.Find(1);
StringBuilder sb = new StringBuilder()
foreach (Standard s in stdRep.FindByAgencyID(project.Agency.ID))
{
Requirement r = new Requirement();
r.Project = project;
r.Standard = s;
r.DateCompleted = (DateTime)SqlDateTime.MaxValue;
r.DateDue = DateTime.Now.AddDays(90);
r = reqRep.Save(r);
sb.AppendLine(String.Format("Saved Requirement ID {0} with Project ID {1}<br>", r.ID, r.Project.ID));
}
return sb.ToString();
}
}
And here is associated repository code:
public class ProjectRepository
{
public Project Find(int id)
{
using (var db = new MyContext())
{
return db.Projects
.Include(p => p.Agency)
.Include(p => p.Department)
.First(p => p.ID.Equals(id));
}
}
}
public class StandardRepository
{
public List<Standard> FindByAgencyID(int agencyID)
{
using (var db = new MyContext())
{
return db.Standards.Where(r => r.AgencyID == agencyID).ToList();
}
}
}
public class RequirementRepository
{
public Requirement Save(Requirement requirement)
{
using (var db = new MyContext())
{
Requirement retVal = requirement;
if (requirement.ID.Equals(0))
{
retVal = db.Requirements.Add(requirement);
}
else
{
db.Entry(requirement).State = EntityState.Modified;
}
db.SaveChanges();
return retVal;
}
}
}
When I run this method, I expect it to insert a number of new Requirements into the database with the project ID of 1 and a standard ID of whatever standard it's on. Instead, it creates a whole new project and a whole new standard for every requirement it adds, then assigns those IDs to the requirement.
Each context keeps track of the entities loaded, modified and the entities added.
Your repositories need to look something like this....
public class StandardRepository
{
MyContext _context;
public StandardRepository(MyContext context)
{
_context = context;
}
public List<Standard> FindByAgencyID(int agencyID)
{
return _context.Standards.Where(r => r.AgencyID == agencyID).ToList();
}
}
public class RequirementRepository
{
MyContext _context;
public RequirementRepository(MyContext context)
{
_context = context;
}
public Requirement Save(Requirement requirement)
{
Requirement retVal = requirement;
if (requirement.ID.Equals(0))
{
retVal = _context.Requirements.Add(requirement);
}
else
{
_context.Entry(requirement).State = EntityState.Modified;
}
_context.SaveChanges();
return retVal;
}
}
public class RequirementRepository
{
public static string CreateMockData()
{
using(MyContext context = new MyContext())
{
StandardRepository stdRep = new StandardRepository(context);
ProjectRepository projRep = new ProjectRepository(context);
RequirementRepository reqRep = new RequirementRepository(context);
Project project = projRep.Find(1);
StringBuilder sb = new StringBuilder()
foreach (Standard s in stdRep.FindByAgencyID(project.Agency.ID))
{
Requirement r = new Requirement();
r.Project = project;
r.Standard = s;
r.DateCompleted = (DateTime)SqlDateTime.MaxValue;
r.DateDue = DateTime.Now.AddDays(90);
r = reqRep.Save(r);
sb.AppendLine(String.Format("Saved Requirement ID {0} with Project ID {1}<br>", r.ID, r.Project.ID));
}
}
return sb.ToString();
}
}
From my understanding, you shouldn't have to manually set the state of the object you have modified unless you have detached it from its context. EF keeps track of the object state.
I like to use something like this:
public abstract class EntityRepositoryBase<TEntity> : IDisposable, IEntityRepositoryBase<TEntity> where TEntity : class , IEntityWithId
{
protected EntityRepositoryBase()
{
Context = new SomeEntities();
}
public abstract ObjectSet<TEntity> EntityCollection { get; }
public SomeEntities Context { get; set; }
public TEntity GetById(int id)
{
return EntityCollection
.FirstOrDefault(x => x.Id == id);
}
public void Dispose()
{
Context.Dispose();
}
}
Then in the deriving repositories:
public class AnswerRepository : EntityRepositoryBase<AnswerEntity>, IAnswerRepository
{
public override ObjectSet<AnswerEntity> EntityCollection
{
get { return Context.AnswerEntities; }
}
}
I inject the Repositories into the relevant class using ninject but you should be able to get similar with:
using (var repo = new AnswerRepository())
{
// modifying via Context
var someEntity = repo.GetById(someId);
someEntity.Value = "1";
repo.Context.SaveChanges();
//modifying via repo
repo.Delete(anotherEntity);
}
and then doing what you need to do. The context is exposed via the interface IEntityRepositoryBase should you need to perform out-of-repository modifications and then SaveChanges() as well as any specific CRUD type methods in your repo. Once out of scope the object and the underlying connection will be closed.