Reputation: 50
I'm having some issues with Entity Framework on .NET Framework. My app is designed as such:
I have my class that inherits from DbContext
and I have this property:
public DbSet<User> Users { get; set; }
// ...other properties
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<UserManageableZones>()
.HasRequired(umz => umz.User)
.WithMany(u => u.ManageableZones)
.HasForeignKey(umz => umz.Username)
.WillCascadeOnDelete(false);
}
My User
model is something like this:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Required]
[MaxLength(128)]
[Column("USERNAME")]
public string Username { get; set; } = string.Empty;
public virtual ICollection<UserManageableZones> ManageableZones { get; set; }
public User()
{
ManageableZones = new HashSet<UserManageableZones>();
}
As you can see, I have the property ManageableZones
, that is the table I want to relate with, with a 1-to-many relationship. So basically one user can have many UserManageableZones
(for simplicity's sake, a zone can be related with only 1 user, logically this is incorrect, but I don't care about having a many-to-many relationship).
This is my UserManageableZones
:
public virtual User User { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
[Column("ID")]
public int Id { get; set; }
[ForeignKey("User")]
[Required]
[Column("USERNAME")]
public string Username { get; set; }
// ...other properties
Then, I have a class that is basically a projection of the data from my database:
public Class DataContext
{
public List<User> Users {get; set;}
public DataContext()
{
Users = new List<User>();
}
}
DataContext
is the "static" object with which I'll interact with data, adding/deleting/updating and so on. Then I'll save this data back to the database.
To do so, I have a DataAccess
class, that basically inits the DataContext
by populating all its properties with database's data, and updating database data with the one from the DataContext
.
To save the data into the database, I have this, IMO, horrible method that unfortunately I didn't really understand how it works, so I didn't really ever touch it
private void SaveTable<T1, T2>(List<T1> entity, bool canUpdate = true, bool canDelete = true)
where T1 : class
{
PrintCallStack(false);
try
{
AMMContext db;
if (AMMContext.DbType == Entity.eDbType.SqLite)
db = new AMMContext(AMMContext.LoadConnectionString());
else
db = new AMMContext();
using (db)
{
List<T1> listInDB = (List<T1>)Activator.CreateInstance(typeof(List<T1>));
DbSet<T1> dbSet = null;
foreach (PropertyInfo pInfo in typeof(AMMContext).GetProperties())
{
if (pInfo.GetValue(db) != null)
{
if (pInfo.GetValue(db).GetType() == typeof(DbSet<T1>))
{
dbSet = (DbSet<T1>)pInfo.GetValue(db);
listInDB = dbSet.ToList();
}
}
}
List<T2> idEntityList = null;
if (entity != null)
idEntityList = entity.Select(y => (T2)GetPrimaryKeyValue(y)).ToList();
//List<T1> updating = entity.Where(x => idListinDb.Contains((T2)GetPrimaryKeyValue(x))).ToList();
//List<T1> adding = entity.Where(x => !idListinDb.Contains((T2)GetPrimaryKeyValue(x))).ToList();
if (canUpdate)
dbSet.AddOrUpdate(entity.ToArray());
if (canDelete)
{
List<T1> deleting = dbSet.ToList().Where(x => !idEntityList.Contains((T2)GetPrimaryKeyValue(x))).ToList();
deleting.ForEach(x => dbSet.Attach(x));
dbSet.RemoveRange(deleting);
}
db.SaveChanges();
}
}
catch (Exception e)
{
try
{
PrintCallStack(true);
Log.ErrorFormat($"DataAccess.Save error, transaction rollback occurred | exc:{e.InnerException.InnerException.Message}");
}
catch (Exception ex)
{
Log.ErrorFormat($"DataAccess.Save error, rollback procedure failure");
StringBuilder sb = new StringBuilder();
sb.Append("For entity type : ");
if (entity != null)
{
foreach (T1 item in entity)
{
sb.Append(item.GetType().Name);
sb.Append(" - ");
}
}
Log.ErrorFormat(sb.ToString());
}
}
}
This method is called by the DataAccess
all around the code, wrapped inside another method that does something like this
public void Save(bool allFilter = true, bool usersFilter = false, ...other filters)
{
if (ammUsersFilter | allFilter)
SaveTable<User, string>(entity: DataContext.Users, canUpdate: true, canDelete: !initialConditions);
// ...same for other filters
}
That's about it. The problem is that the collection of UserManageableZones
inside User
, it's not getting saved in its table. As it is right now, when the app starts from scratch, the database is created and also the table USER_ZONES
is created.
I've tried to manually create a record inside the USER_ZONES
table, then boot up the app and saw that when the data is gathered from the database, I actually have that record inside the user. This makes me think that relation wise, my work is correct. But I have no clue about what I'm missing.
Ah, just to mention. Inside my USER
table, I have no column related to USER_ZONES
, but I think it's correct. That's it.
These are the script generated of both tables
CREATE TABLE AMM_USER
(
USERNAME VARCHAR(128) NOT NULL,
...
CONSTRAINT PK_AMM_USER PRIMARY KEY (USERNAME)
);
CREATE TABLE USER_ZONES
(
ID INTEGER NOT NULL,
USERNAME VARCHAR(128) NOT NULL,
CONSTRAINT PK_USER_ZONES PRIMARY KEY (ID),
CONSTRAINT FK_USER_ZONES_AMM_USER_USERNAME FOREIGN KEY (USERNAME) REFERENCES AMM_USER(USERNAME)
);
CREATE INDEX FK_USER_ZONES_AMM_USER_USERNAME ON USER_ZONES (USERNAME);
CREATE INDEX IX_USER_ZONES_USERNAME ON USER_ZONES (USERNAME);
Upvotes: 0
Views: 34