I tried to add entities to the database with Entity Framework, but it failed. Here is the source code that is responsible for adding a list of entities to the database:
public class EfUserPermissionRepository : IUserPermissionDal
{
private readonly EfDbContext _context;
public EfUserPermissionRepository(EfDbContext context)
{
if (context == null)
throw new ArgumentNullException(typeof(EfDbContext).ToString());
this._context = context;
}
//It adds USERPERMISSION list to database.
public void Add(List<USERPERMISSION> entities)
{
try
{
if (entities == null || !entities.Any())
throw new ArgumentNullException();
foreach (USERPERMISSION value in entities)
{
if (value == null)
continue;
this._context.USERPERMISSION.Add(value);
}
this._context.SaveChanges();
}
catch (Exception exception)
{
throw exception;
}
}
public USERPERMISSION Add(USERPERMISSION entity)
{
_context.USERPERMISSION.Add(entity);
_context.SaveChanges();
return entity;
}
}
I have a class named USERPERMISSION. It has two foreign key relations with the other class named USER and PAGE. Here is the content of the USERPERMISSION class:
[Table("USERPERMISSION")]
public class USERPERMISSION
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey("USER")]
public int USERID { get; set; }
[ForeignKey("PAGE")]
public int PAGEID { get; set; }
public int? ADD { get; set; }
public int? EDIT { get; set; }
public int? DELETE { get; set; }
public int? READ { get; set; }
public int? LIST { get; set; }
public int? REPORT { get; set; }
public int? PUBLISH { get; set; }
public int? CONFIRM { get; set; }
public int ACTIVE { get; set; }
[StringLength(30)]
public string CODE { get; set; }
public virtual USER USER { get; set; }
public virtual PAGE PAGE { get; set; }
}
In order to test the Add method defined in EfUserPermissionRepository, I devised a test code. I get all USERPERMISSION of user 1 and copy it to user 2. Currently, user 1 has 26 user permissions, whereas user 2 has not got any USERPERMISSION. My intention is to copy all USERPERMISSION lists of user 1 to user 2 and save them to the database. Here is the test code:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PROJECT.Tests.Soyut;
using PROJECT.Entity.Models;
using System.Collections.Generic;
using System.Linq;
namespace PROJECT.Tests
{
[TestClass]
public class UserPermissionManagerTest : TestBase
{
private int UserId1 { get; set; }
private USER User2 { get; set; }
private List<USERPERMISSION> UserPermissionList1 { get; set; }
/// <summary>
/// The procedure where the <code>Add</code> procedure was tested against user 2.
///
/// It is hoped that it will be successful.
/// </summary>
[TestMethod]
public void USERPERMISSIONAdd_001()
{
//’UserPermissionManageri’ is a Business layer component that emerges from TestBase.
List<USERPERMISSION> list = UserPermissionManageri.Add(UserPermissionList1);
Assert.IsNotNull(list);
Assert.AreEqual(true, list.Any());
}
[TestInitialize]
public void TestClassInitialize()
{
UserId1 = 1;
//’UserManageri’ is a Business layer component that emerges from TestBase.
User2 = UserManageri.Get(2);
Assert.IsNotNull(User2);
//Creates a new list by getting all user permission list of user 1 to user 2.
UserPermissionList1 = this.CopyUserPermissionList(UserId1, User2);
Assert.IsNotNull(UserPermissionList1);
Assert.AreEqual(true, UserPermissionList1.Any());
}
private List<USERPERMISSION> CopyUserPermissionList(int sourceUserId, USER targetUserToCopy)
{
//getting all user permission list of the sourceUserId.
List<USERPERMISSION> list = UserPermissionManageri.List(p => p.USERID == sourceUserId);
//ensure that the list is not null.
Assert.IsNotNull(list);
//ensure that the list has a value.
Assert.AreEqual(true, list.Any());
List<USERPERMISSION> copyList = new List<USERPERMISSION>();
//copying the list to the copylist
foreach (USERPERMISSION value in list)
{
if (value == null)
continue;
copyList.Add(new USERPERMISSION()
{
USERID = value.USERID,
PAGEID = value.PAGEID,
ADD = value.ADD,
EDIT = value.EDIT,
DELETE = value.DELETE,
READ = value.READ,
LIST = value.LIST,
REPORT = value.REPORT,
PUBLISH = value.PUBLISH,
CONFIRM = value.CONFIRM,
ACTIVE = value.ACTIVE,
CODE = value.CODE,
USER = value.USER,
PAGE = value.PAGE,
ID = 0
});
}
//assigning targetUserToCopy to all elements of copyList
foreach (USERPERMISSION permission in copyList)
{
if (permission == null)
continue;
permission.USER = targetUserToCopy;
permission.USERID = targetUserToCopy.ID;
}
//returning the copylist.
return copyList;
}
}
}
USERPERMISSIONAdd_001 runs successfully, that is, test function is green when I run it; however, it does not make any changes in the database. Where am I wrong? Thanks in advance.
As Panagiotis Kanavos pointed out, I start by isolating the problem. I discard the UserPermissionManageri in test UserPermissionManagerTest and create a new DbContext in UserPermissionManagerTest. Test class looks like this:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PROJECT.Tests.Soyut;
using PROJECT.Entity.Models;
using System.Collections.Generic;
using System.Linq;
using PROJECT.Dal.Concrete.EntityFramework;
namespace PROJECT.Tests.Concrete.BusinessLayer
{
[TestClass]
public class UserPermissionManagerTest : TestBase
{
private int UserId1 { get; set; }
private USER User2 { get; set; }
private List<USERPERMISSION> UserPermissionList1 { get; set; }
private static EfDbContext EfDbContexti { get; set; }
/// <summary>
/// The procedure where the <code>Add</code> procedure was tested against user 1665.
///
/// It is hoped that it will be successful.
/// </summary>
[TestMethod]
public void USERPERMISSIONAdd_001()
{
IEnumerable<USERPERMISSION> list = EfDbContexti.USERPERMISSION.AddRange(UserPermissionList1);
EfDbContexti.SaveChanges();
Assert.IsNotNull(list);
Assert.AreEqual(true, list.Any());
}
[TestInitialize]
public void TestClassInitialize()
{
UserId1 = 17;
EfDbContexti = new EfDbContext();
User2 = EfDbContexti.USER.FirstOrDefault(p => p.ID == 1665);
//User2 = UserManageri.Get(1665);
Assert.IsNotNull(User2);
//Creates a new list by getting all user permission list of user 17 to user 1665
UserPermissionList1 = this.CopyUserPermissionList(UserId1, User2);
Assert.IsNotNull(UserPermissionList1);
Assert.AreEqual(true, UserPermissionList1.Any());
}
[ClassCleanup]
public static void TestClassCleanup()
{
if (EfDbContexti != null)
{
EfDbContexti.SaveChanges();
EfDbContexti.Dispose();
EfDbContexti = null;
}
}
private List<USERPERMISSION> CopyUserPermissionList(int sourceUserId, USER targetUserToCopy)
{
//getting all user permission list of the sourceUserId.
IQueryable< USERPERMISSION> iqueryable = EfDbContexti.USERPERMISSION.Where(p => p.USERID == sourceUserId);
Assert.IsNotNull(iqueryable);
List<USERPERMISSION> list = iqueryable.ToList();
//ensure that list is not null.
Assert.IsNotNull(list);
//ensure that list has a value.
Assert.AreEqual(true, list.Any());
List<USERPERMISSION> copyList = new List<USERPERMISSION>();
//copying the list to copylist
foreach (USERPERMISSION value in list)
{
if (value == null)
continue;
copyList.Add(new USERPERMISSION()
{
USERID = value.USERID,
PAGEID = value.PAGEID,
ADD = value.ADD,
EDIT = value.EDIT,
DELETE = value.DELETE,
READ = value.READ,
LIST = value.LIST,
REPORT = value.REPORT,
PUBLISH = value.PUBLISH,
CONFIRM = value.CONFIRM,
ACTIVE = value.ACTIVE,
CODE = value.CODE,
USER = value.USER,
PAGE = value.PAGE,
ID = 0
});
}
//assigning targetUserToCopy to all elements of copyList
foreach (USERPERMISSION permission in copyList)
{
if (permission == null)
continue;
permission.USER = targetUserToCopy;
permission.USERID = targetUserToCopy.ID;
}
//returning the copylist.
return copyList;
}
}
}
Since TestBase has another independent DbContext variable, this situation causes the exception below:
Entity object cannot be referenced by multiple instances of IEntityChangeTracker. while adding related objects to entity in Entity Framework.
When I remove the inheritance between UserPermissionManagerTest and TestBase the problem has disappeared and relevant records are successfully saved to the database.