EF6 duplicate entries on related entities - c#

Ok, so I'm really frustrated with the duplication issues of EF6. I have searched the forum extensively and tried different things, but I can't seem to figure this one out.
My base model is a trainingprogram, that consists of many blocks, which in turn hold a list of circuits. Every circuit holds a number of exercisesets and progressions for each exercise. All the relevant parts of the model are in the minimal workin example below.
I have a controller that I use to persist training programs to the DB. Whenever I call dbcontext.SaveChanges(), my database i populated with duplicates of the related entities, although I have tried setting the state to unchanged, attaching the enities to the context and what not. Pretty much everything gets duplicated - exercises, categories and progressionschemes.
This is really a blocker, so any help is appreciated.
[HttpPost]
[Route("Add")]
public HttpResponseMessage AddProgram(TrainingProgram program)
{
int id = -1;
try
{
using (var dbcontext = new ApplicationDbContext())
{
foreach (TrainingBlock b in program.Blocks)
foreach (ExercisePairing c in b.Circuits)
{
foreach (ProgressionScheme ps in c.Progressions.Select(x => x.Progression).Distinct().ToList())
{
var ep = dbcontext.Progressions.FirstOrDefault(p => p.Name == ps.Name && p.Id == ps.Id);
if (ep is null)
dbcontext.Progressions.Attach(ps);
//dbcontext.Entry(ps).State = EntityState.Unchanged;// Attach(ps);
}
foreach (Exercise s in c.Sets.Select(x => x.Exercise).Distinct().ToList())
{
//dbcontext.Entry(s).State = EntityState.Unchanged;
//dbcontext.Entry(s.Category).State = EntityState.Unchanged;
dbcontext.ExerciseCategories.Attach(s.Category);
dbcontext.Exercises.Attach(s);
}
}
dbcontext.TrainingPrograms.AddOrUpdate(program);
dbcontext.SaveChanges();
id = program.Id;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
return Request.CreateResponse(HttpStatusCode.OK, id);
}
public class ExercisePairing:BaseClass
{
private List<ExerciseSet> sets = new List<ExerciseSet>();
private List<ProgressionForExercise> progressions = new List<ProgressionForExercise>();
private int id;
...
...
}
}
public class ProgressionForExercise:BaseClass
{
public int Id { get; set; }
private Exercise exercise;
public int ExerciseId { get; set; }
public int ProgressionId { get; set; }
[ForeignKey("ExerciseId")]
public Exercise Exercise
{
get => exercise;
set
{
exercise = value;
ExerciseId = exercise.Id;
}
}
private ProgressionScheme progression;
[ForeignKey("ProgressionId")]
public ProgressionScheme Progression
{
get =>progression ;
set
{
progression = value;
ProgressionId = progression.Id;
}
}
}
public class Exercise : BaseClass
{
private int id;
private string name;
private string description;
private string videourl;
private ExerciseCategory category;
public int CategoryId { get; set; }
[ForeignKey("CategoryId")]
public ExerciseCategory Category
{
get => category;
set
{
category = value;
OnPropertyChanged();
}
}
public int Id
{
get => id;
set
{
id = value;
OnPropertyChanged();
}
}
...
...
}
public class ExerciseCategory:BaseClass
{
private string name;
private int id;
[Key]
public int Id
{
get => id;
set
{
id = value;
OnPropertyChanged();
}
}
public string Name
{
get => name;
set
{
name = value;
OnPropertyChanged();
}
}
...
...
}
public class ProgressionScheme:BaseClass
{
private int id;
private string name;
private string description;
public int Id
{
get => id;
set
{
id = value;
OnPropertyChanged();
}
}
public string Name
{
get => name;
set
{
name = value;
OnPropertyChanged();
}
}
...
...
}
EDIT
I now solved the issue by basically re-wrtiting my controller code like so:
[HttpPost]
[Route("Add")]
public HttpResponseMessage AddProgram(TrainingProgram program)
{
int id = -1;
try
{
using (var dbcontext = new ApplicationDbContext())
{
TrainingProgram tp = new TrainingProgram();
tp.Title = program.Title;
tp.Remarks = program.Remarks;
tp.CreationDate = program.CreationDate;
tp.Creator = program.Creator;
tp.Blocks = new List<TrainingBlock>();
foreach (TrainingBlock b in program.Blocks)
{
TrainingBlock tb = new TrainingBlock();
tb.Title = b.Title;
tb.Remarks = b.Remarks;
tb.Circuits = new List<ExercisePairing>();
foreach (ExercisePairing c in b.Circuits)
{
ExercisePairing ep = new ExercisePairing();
ep.Sets = new List<ExerciseSet>();
foreach(ExerciseSet s in c.Sets)
{
ExerciseSet es = new ExerciseSet();
Exercise ex = dbcontext.Exercises.Find(s.Exercise.Id);
es.Exercise = ex;
ExerciseCategory ec = dbcontext.ExerciseCategories.Find(s.Exercise.Category.Id);
es.Exercise.Category = ec;
es.Reps = s.Reps;
es.Intensity = s.Intensity;
es.Unit = s.Unit;
ep.Sets.Add(es);
}
ep.Progressions = new List<ProgressionForExercise>();
foreach (ProgressionForExercise pro in c.Progressions)
{
Exercise ex = dbcontext.Exercises.Find(pro.Exercise.Id);
ProgressionScheme ps = dbcontext.Progressions.Find(pro.Progression.Id);
ProgressionForExercise p4e = new ProgressionForExercise();
p4e.Exercise = ex;
p4e.Progression = ps;
ep.Progressions.Add(p4e);
}
tb.Circuits.Add(ep);
}
tp.Blocks.Add(tb);
}
dbcontext.TrainingPrograms.AddOrUpdate(tp);
dbcontext.SaveChanges();
id = tp.Id;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
return Request.CreateResponse(HttpStatusCode.OK, id);
}
So in essence, I am avoiding the duplicates by only using the very objects that are present in the Context. Although this works, I am not sure if I am happy with that. If a simple CRUD peration takes that much code, I fail to see the upside of using EF VS simply using an SQL insert statement, which would be much more efficient in this case IMHO. Also, why does EF ignore the primary keys and insist on using its wn instances of my enitities? All of this is very strange.

Related

Can't search for the max value into an array

My problem is that i can't search into an array using linq in order to find an object property and set that as an id.
I need the method to search in the array for other model.idCliente and set that value as the "nextid + 1", in order to use it as id and the next array index.
Since the array's empty, the program adds the new object correctly, but when entering in the else if case, i get an axception for "a as null".
This is my code (where i get an exception on the else if linq line saying that "a" is null):
//Arrays
ClienteModel[] MemoryClienti = new ClienteModel[19];
OrdineModel[] MemoryOrdini = new OrdineModel[19];
//Aggiungi
public bool CreateCliente(ClienteModel model)
{
if (MemoryClienti[0] == null)
{
int defaultID = 0;
int defaultIndex = 0;
model.IDCliente = defaultID;
MemoryClienti[defaultIndex] = model;
}
else if (MemoryClienti[0]!=null)
{
var maxID = MemoryClienti.Max(a => a.IDCliente);
model.IDCliente = maxID++;
MemoryClienti[maxID++] = model;
}
return true;
}
This is the code of the form click:
//Aggiungi Cliente
private void aggiungiClienteButton_Click(object sender, EventArgs e)
{
clienteModel.Cognome = cognomeTextBox.Text;
clienteModel.Nome = nomeTextBox.Text;
clienteModel.Indirizzo = indirizzoTextbox.Text;
dbMemoryManager.CreateCliente(clienteModel);
MessageBox.Show("Cliente aggiunto correttamente.");
cognomeTextBox.Text = String.Empty;
nomeTextBox.Text = String.Empty;
indirizzoTextbox.Text = String.Empty;
}
This is the ClienteModel class:
public class ClienteModel
{
public int IDCliente { get; set; }
public string Cognome { get; set; }
public string Nome { get; set; }
public string Indirizzo { get; set; }
}
Wouldn't the following code achieve what you are trying to do?
ClienteModel[] MemoryClienti = new ClienteModel[19];
OrdineModel[] MemoryOrdini = new OrdineModel[19];
int maxID = 0; /* 0 is not a valid ID. IDs start from 1 */
//Aggiungi
public bool CreateCliente(ClienteModel model)
{
if(maxID <= MemoryClienti.Length) {
MemoryClienti[maxID++] = model; // copy the reference
model.IDCliente = maxID; // update the object's ID
return true;
} else {
return false; // can't add. array is full
}
}
If you are also doing deletions, you are better off using a List as others have also suggested.

CRUD over two different collections of POCOs

I have an interesting question, one I'm having difficulty searching for an answer on.
I have two IEnumerable collections of objects. The underlying objects are completely separate, BUT I can identify a shared key that should match. The collections are important, in that my "left" object is the "system of record", and the "right" object is representing a system I need to ensure matches the system of record.
Once they are matched, I need to perform CRUD operations on one side to bring the right side in line with the left side. For example, it would create a new item on the right side if one didn't exist, or update values, or delete if the item was missing on the left, but not the right.
The catch is, I have hundreds of these collections to match up, and the actual CRUD code is different.
I'd like to introduce some shared code where I can pass in both collections, the collection types (as probably generics), some kind of comparer, and some delegates of what operation to perform for CRUD.
If this code actually existed, it may look something like this
class Stuff
{
string Id {get; set;}
string Name {get; set;}
}
class Junk
{
string Id {get; set;}
string ShortName {get; set;}
}
IEnumerable<Stuff> myStuff = GetStuff();
IEnumerable<Junk> myJunk = GetJunk();
CrudComparer cc = new CrudComparer<Stuff, Junk>(myStuff, myJunk);
cc.Comparer = (leftObject, rightObject) => {
leftObject.Name == rightObject.Name
}
cc.CreateOperation = (newObject, rightCollection) => {
Junk j = new Junk();
j.Shortname = newObject.Name;
rightCollection.Add(j);
}
cc.UpdateOperation = (leftObject, rightObject) => {
rightObject.Shortname = leftObject.Name;
}
cc.DeleteOperation = (rightCollection, rightObject) => {
rightCollection.Remove(rightObject);
}
cc.Compare();
Has anyone ever seen code that does something like this? I'd hate to reinvent the wheel if I can grab something already done.
Thanks for any help!
--Michael
I got to thinking more about this, and realized what I knew about delgates and generics should be sufficient to solve this problem, so I got in LinqPad and had some fun. I haven't written any unit tests around this yet, so use at your own risk, but hopefully if you want to use this you understand the underlying concepts.
class Blah
{
public int ID { get; set; }
public string BlahName { get; set;}
}
class Bleh
{
public int ID { get; set; }
public string BlehName { get; set;}
}
class CrudComparer<TLeft, TRight>
{
private readonly ICollection<TLeft> _leftCollection;
private readonly ICollection<TRight> _rightCollection;
private readonly Comparer _compareOperation;
private readonly CreateOperation _createOperation;
private readonly UpdateOperation _updateOperation;
private readonly DeleteOperation _deleteOperation;
public delegate bool Comparer(TLeft leftItem, TRight rightItem);
public delegate void CreateOperation(TLeft leftItem, ICollection<TRight> rightCollection);
public delegate void UpdateOperation(TLeft leftItem, TRight rightItem);
public delegate void DeleteOperation(TRight rightItem, ICollection<TRight> rightCollection);
public CrudComparer(ICollection<TLeft> leftCollection, ICollection<TRight> rightCollection, Comparer compareOperation, CreateOperation createOperation, UpdateOperation updateOperation, DeleteOperation deleteOperation)
{
_leftCollection = leftCollection;
_rightCollection = rightCollection;
_compareOperation = compareOperation;
_createOperation = createOperation;
_updateOperation = updateOperation;
_deleteOperation = deleteOperation;
}
public void Compare()
{
foreach (TLeft leftItem in _leftCollection)
{
bool foundItem = false;
foreach (TRight rightItem in _rightCollection)
{
if (_compareOperation(leftItem, rightItem))
{
//these equal
foundItem = true;
}
}
if (foundItem == false)
{
_createOperation(leftItem, _rightCollection);
}
}
List<TRight> itemsToDelete = new List<TRight>();
foreach (TRight rightItem in _rightCollection)
{
bool foundItem = false;
foreach (TLeft leftItem in _leftCollection)
{
if (_compareOperation(leftItem, rightItem))
{
foundItem = true;
_updateOperation(leftItem, rightItem);
break;
}
}
if (!foundItem)
{
itemsToDelete.Add(rightItem);
}
}
foreach (TRight itemToDelete in itemsToDelete)
{
_deleteOperation(itemToDelete, _rightCollection);
}
}
}
void Main()
{
List<Blah> blahItems = new List<Blah>();
blahItems.Add(new Blah() { ID = 1, BlahName = "Blah" });
blahItems.Add(new Blah() { ID = 2, BlahName = "ABC" });
blahItems.Add(new Blah() { ID = 34, BlahName = "XYZ" });
blahItems.Add(new Blah() { ID = 6442, BlahName = "123" });
List<Bleh> blehItems = new List<Bleh>();
blehItems.Add(new Bleh() { ID = 2, BlehName = "12345"});
blehItems.Add(new Bleh() { ID = 6, BlehName = "43232"});
blehItems.Add(new Bleh() { ID = 77, BlehName = "BlahBlah"});
blehItems.Add(new Bleh() { ID = 2334, BlehName = "ZYX"});
CrudComparer<Blah, Bleh>.Comparer compareOperation = (leftObject, rightObject) =>
{
return leftObject.ID == rightObject.ID;
};
CrudComparer<Blah, Bleh>.CreateOperation createOperation = (leftObject, rightCollection) =>
{
rightCollection.Add(new Bleh() { ID = leftObject.ID });
};
CrudComparer<Blah, Bleh>.UpdateOperation updateOperation = (leftObject, rightObject) =>
{
rightObject.BlehName = leftObject.BlahName;
};
CrudComparer<Blah, Bleh>.DeleteOperation deleteOperation = (rightObject, rightCollection) =>
{
rightCollection.Remove(rightObject);
};
CrudComparer<Blah, Bleh> cc = new CrudComparer<Blah, Bleh>(blahItems, blehItems, compareOperation, createOperation, updateOperation, deleteOperation);
cc.Compare();
}

Combining lists of objects containing lists of objects in c# [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
The title is a little prosaic, I know. I have 3 classes (Users, Cases, Offices). Users and Cases contain a list of Offices inside of them. I need to compare the Office lists from Users and Cases and if the ID's of Offices match, I need to add those IDs from Cases to the Users. So the end goal is to have the Users class have any Offices that match the Offices in the Cases class.
To add clarity, I am looking to compare the two officeLists (users.officeList and cases.OfficeList) and when any Cases.OfficeList.ID == Users.OfficeList.ID, I need to add that Case.ID to the list of Users.caseAdminIDList
Any ideas?
My code (which isnt working)
foreach (Users users in userList)
foreach (Cases cases in caseList)
foreach (Offices userOffice in users.officeList)
foreach (Offices caseOffice in cases.officeList)
{
if (userOffice.ID == caseOffice.ID)
users.caseAdminIDList.Add(cases.adminID);
}//end foreach
//start my data classes
class Users
{
public Users()
{
List<Offices> officeList = new List<Offices>();
List<int> caseAdminIDList = new List<int>();
ID = 0;
}//end constructor
public int ID { get; set; }
public string name { get; set; }
public int adminID { get; set; }
public string ADuserName { get; set; }
public bool alreadyInDB { get; set; }
public bool alreadyInAdminDB { get; set; }
public bool deleted { get; set; }
public List<int> caseAdminIDList { get; set; }
public List<Offices> officeList { get; set; }
}
class Offices
{
public int ID { get; set; }
public string name { get; set; }
}
class Cases
{
public Cases()
{
List<Offices> officeList = new List<Offices>();
ID = 0;
}//end constructor
public int ID { get; set; }
public string name { get; set; }
public int adminID { get; set; }
public bool alreadyInDB { get; set; }
public bool deleted { get; set; }
public List<Offices> officeList { get; set; }
}
//in my main method
private bool grabCasesFromAdminDB() //gets cases from DB1 (AdminDB)
{
DatabaseIO dbIO = new DatabaseIO();
caseList = dbIO.getCasesFromAdminDB(adminDBConString, caseList).ToList();
if (dbIO.errorMessage == null || dbIO.errorMessage.Equals(""))
{
if (getCaseOfficeRelationship())
return true;
else
return false;
}//end if
else
{
MessageBox.Show(dbIO.errorMessage, "Admin DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}//end else
}//end method
private bool grabCasesFromListDB()//grabs cases from the main db
{
DatabaseIO dbIO = new DatabaseIO();
caseList = dbIO.getCasesFromMainDB(connectionString, caseList).ToList();
if (dbIO.errorMessage == null || dbIO.errorMessage.Equals(""))
return true;
else
{
MessageBox.Show(dbIO.errorMessage, "Main DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}//end else
}//end method
private bool getCaseOfficeRelationship()//adds office relationship to cases
{
DatabaseIO dbIO = new DatabaseIO();
caseList = dbIO.getOfficeToCaseRelationship(connectionString, caseList).ToList();
if (dbIO.errorMessage == null || dbIO.errorMessage.Equals(""))
{
if (getOfficeNamesByID())
return true;
else
return false;
}//end if
else
{
MessageBox.Show(dbIO.errorMessage, "Cases To Offices Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}//end else
}//end method
private bool getOfficeNamesByID()//grabs the id of the offices by name
{
List<Offices> officeList = new List<Offices>();
DatabaseIO dbIO = new DatabaseIO();
officeList = dbIO.getOfficeNamesByOfficeID(connectionString).ToList();
if (dbIO.errorMessage == null || dbIO.errorMessage.Equals(""))
{
matchOfficeNamesToIDs(officeList);
return true;
}//end if
else
{
MessageBox.Show(dbIO.errorMessage, "Getting Office List Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}//end else
}//end method
private void matchOfficeNamesToIDs(List<Offices> officeList)
{
foreach (Cases cases in caseList)
if (cases.officeList != null)
foreach (Offices office in cases.officeList)
{
foreach (Offices innerOffice in officeList)
if (innerOffice.ID == office.ID)
office.name = innerOffice.name;
}//end foreach
}//end method
//an example of my DBIO class
public List<Cases> getCasesFromAdminDB(string adminDBConString, List<Cases> caseList)
{
try
{
Cases cases = null;
SqlConnection con = new SqlConnection();
con.ConnectionString = adminDBConString;
con.Open();
SqlCommand command = new SqlCommand();
command.Connection = con;
command.CommandText = "select CS_Case_ID, Case_Name from CS_Case where CS_Product_Type_ID = 2 and CS_Case_Status_ID = 1";
SqlDataReader thisReader = command.ExecuteReader();
int idxID = thisReader.GetOrdinal("CS_Case_ID");
int idxName = thisReader.GetOrdinal("Case_Name");
while (thisReader.Read())
{
bool found = false;
foreach (Cases tempCase in caseList)
{
if (tempCase.adminID == Int32.Parse(thisReader.GetValue(idxID).ToString()))
{
tempCase.alreadyInDB = true;
found = true;
}//end if
}//end foreach
if (!found)
{
cases = new Cases();
cases.adminID = Int32.Parse(thisReader.GetValue(idxID).ToString());
cases.name = thisReader.GetValue(idxName).ToString();
cases.alreadyInDB = false;
cases.officeList = new List<Offices>();
caseList.Add(cases);
}//end if
}//end while
thisReader.Close();
return caseList;
}//end try
catch (Exception excep1)
{
errorMessage = "Cases could not be loaded from the Admin Console." + "\r\n" + "Error message: " + excep1.ToString();
return caseList;
}//end catch
}//end method
Complex querying like this is best handled by LINQ. If you had a common element on both Users and Cases, then this would be a job for a join. But in this case instead of a common element, they each contain lists, and you want to "join" on those where the two lists have a common element.
So, to start off, what's the condition for a particular case to be included for a user?
case.officeList.Any(caseOffice => user.officeList.Any(userOffice => caseOffice.ID == userOffice.ID))
i.e. Any office in the case's officeList is contained in the user's officeList.
Now we have that condition, we can use it in a LINQ Where clause to pull out all the desired case:
caseList.Where(case =>
case.officeList.Any(caseOffice => user.officeList.Any(userOffice => caseOffice.ID == userOffice.ID)))
That returns our collection of cases, so finally we just want to Select out the part of the case we need, the adminID.
caseList.Where(case =>
case.officeList.Any(caseOffice => user.officeList.Any(userOffice => caseOffice.ID == userOffice.ID)))
.Select(case => case.adminID);
So putting that all together:
foreach(Users users in userList)
{
users.caseAdminIDList = caseList.Where(case =>
case.officeList.Any(caseOffice => user.officeList.Any(userOffice => caseOffice.ID == userOffice.ID)))
.Select(case => case.adminID).ToList();
}
public Cases()
{
List<Offices> officeList = new List<Offices>();
ID = 0;
}//end constructor
This is making a new varaible called officeList. It will not use the officeList outside the constructor.
This needs to be changed to:
officeList = new List<Offices>();
This will properly initialize the class field.
You can implement your Offices class like this:
class Offices:IEquatable<Offices>
{
public int ID { get; set; }
public string name { get; set; }
public bool Equals(Offices other)
{
return this.ID.Equals(other.ID);
}
public override int GetHashCode()
{
return this.ID.GetHashCode();
}
}
Then in your code to have the Users class have any Offices that match the Offices in the Cases class just do this;
usersVariable.CaseAdminIDList = usersVariable.OfficeList.Intersect(casesVariable.OfficeList).Select(o => o.ID).ToList();
Also in your users and cases class you need to initialize the list properly(you are using automatic properties and in ctor declaring and initializing a whole new variable),something
like this for example:
class Users
{
public Users()
{
officeList = new List<Offices>();
caseAdminIDList = new List<int>();
ID = 0;
}//end constructor
private List<Offices> officeList;
public List<Offices> OfficeList
{
get { return officeList; }
set { officeList = value; }
}
private List<int> caseAdminIDList;
public List<int> CaseAdminIDList
{
get { return caseAdminIDList; }
set { caseAdminIDList = value; }
}
//other members.....
}

Statement is not updating data item

I have this LINQ statement that tries to set the 1st element in the collection of string[]. But it doesn't work.
Below is the LINQ statement.
docSpcItem.Where(x => x.DocID == 2146943)
.FirstOrDefault()
.FinishingOptionsDesc[0] = "new value";
public string[] FinishingOptionsDesc
{
get
{
if (this._FinishingOptionsDesc != null)
{
return (string[])this._FinishingOptionsDesc.ToArray(typeof(string));
}
return null;
}
set { this._FinishingOptionsDesc = new ArrayList(value); }
}
What's wrong with my LINQ statement above?
Couple of things.. There are some problems with your get and set. I would just use auto properties like this..
public class DocSpcItem
{
public string[] FinishingOptionsDesc { get; set; }
public int DocID { get; set; }
}
Next for your linq statement, depending on the presence of an item with an id of 2146943 you might be setting a new version of the object rather than the one you intended. This should work..
[TestMethod]
public void Linq()
{
var items = new List<DocSpcItem>();
//2146943
for (var i = 2146930; i <= 2146950; i++)
{
items.Add(new DocSpcItem()
{ DocID = i
, FinishingOptionsDesc = new string[]
{ i.ToString() }
}
);
}
var item = items.FirstOrDefault(i => i.DocID == 2146943);
if (item != null)
{
item.FinishingOptionsDesc = new string[]{"The New Value"};
}
}
and
public class DocSpcItem
{
public string[] FinishingOptionsDesc { get; set; }
public int DocID { get; set; }
}

How to make CRUD m:m relationship c#

How to make CRUD relationship m:m in my model?
Example:
My tables
People (PeopleId, Name)
Thing (ThingId, Name)
PeopleHasThing (PeopleId, ThingId)
My Model
PeopleModel.cs:
public int PeopleId { get; set; }
public string Name
{
get { return _name; }
set
{
if(value == _name) return;
_name = value;
OnPropertyChanged("Name");
}
}
public List<ThingModel> HasThing
{
get { return _hasThing; }
set
{
if(value == _hasThing) return;
_hasThing= value;
OnPropertyChanged("HasThing");
}
}
public static int Insert(PeopleModel m)
{
using (_context = new myDataContext())
{
var d = new People
{
Name = m.Name
Thing = // I don't know how to end this line
};
_context.People.InsertOnSubmit(d);
_context.SubmitChanges();
return d.PeopleId;
}
}
// I don't know how to update or retrieve this from the database
public static void Update(PeopleModel m);
public static void ListAll();
// With this I dont have problem! :P
public static void Delete(int peopleId);
PeopleHasThingModel.cs
public int PeopleId { get; set; }
public int ThingId { get; set; }
ThingModel.cs
public int ThingId { get; set; }
public string Name
{
get { return _name; }
set
{
if(value == _name) return;
_name = value;
OnPropertyChanged("Name");
}
}
public bool IsMarked
{
get { return _isMarked; }
set
{
if(value == _isMarked) return;
_isMarked= value;
OnPropertyChanged("IsMarked");
}
}
Thing is a list in my form are a checkbox list populate from thing table.
Example
I have 3 records in the things table:
1, "house"
2, "dog"
3, "car"
I need to save a new people and her things:
People:
1, "ruben"
PeopleHasThing:
1, 1 -- ruben has house
1, 3 -- ruben has car
Early approach
PeopleModel.cs
public static int Insert(PeopleModel m)
{
using (_context = new myDataContext())
{
var people = new People
{
Name = m.Name
};
// Create the PeopleHasThing record
m.HasThing.ForEach((e) =>
{
people.PeopleHasThing.Add(new PeopleHasThing
{
ThingId = e.ThingId,
People = people
});
});
_context.People.InsertOnSubmit(people);
_context.SubmitChanges();
return people.PeopleId;
}
}
// The following method works!
// I've tried but I have my doubts about deleting records
public static void Update(PeopleModel p)
{
using (_context = new myDataContext())
{
var result = (from r in _context.People
where r.PeopleId == p.PeopleId
select r).SingleOrDefault();
if (null == result) return;
result.Name = p.Name;
//Delete all PeopleHasThings with result.PeopleId ...
EntitySet<PeopleHasThing> set = new EntitySet<PeopleHasThing>();
m.HasThing.ForEach(e =>
{
if (e.IsMarked)
{
set.Add(new PeopleHasThing
{
ThingId = e.ThingId,
People = result
});
}
});
result.PeopleHasThing = set;
_context.SubmitChanges();
}
}
Your 3 models would look like this:
class PeopleModel {
public int PeopleID { get; set; }
public string Name { get; set; }
/* .. additional fields or values .. */
}
class ThingsModel {
public int ThingsID { get; set; }
public string Name { get; set; }
/* .. additional fields or values .. */
}
class PeopleHasThing {
public int PersonID { get; set; }
public int ThingsID { get; set; }
}
You can approach this with the 3 table model by housing only people related fields in the People table & only thing related fields in the Things table.
Then, you would house all of your relationships in the PeopleHasThing table with as many rows as needed.
As you create/edit People & Things, you need to know the ID # to build your relationships
PeopleModel myPerson = new PeopleModel();
myPerson.PeopleID // ID of Person
ThingsModel myThing = new ThingsModel();
myThings.ThingsID // ID of Thing
PeopleHasThings relationship = new PeopleHasThings();
relationship.PeopleID = myPerson.PeopleID;
relationship.ThingsID = myThings.ThingsID;
Example
People:
1, "ruben"
2, "joe"
Things:
1, "house"
2, "dog"
3, "car"
PeopleHasThing:
1, 1 -- ruben has house
1, 3 -- ruben has car
2, 1 -- joe has house

Categories