Getting modified values dynamically - c#

I have got a problem. While updating a row in the table by Linq To Sql,
I want to know the only changed fields.
Suppose I have 25 fields in a page but I only updates 3 fields and at the time of updation, I need to get only those 3 fields, it's old value + it's modified or new value.
Can IT be possible in the Linq To Sql.
I was searching the things on internet and have come to know about DB.GetChangeSet() but it just gives me the modified row.
I have checked other questions related to same from here but I did'nt get the way they were using I also tried but it is giving me error "Sequence contains no elements"
I tried in this way::
where TableClass ObjTbl in the function parameter is the Object containing the new values from the model.
public int UpdateDetails(int Id, TableClass ObjTbl)
{
using (DataContext DB = new DataContext())
{
var Data = DB.TableClass.Where(m => m.PkId == Id).FirstOrDefault();
Data .FirstName = ObjTbl.FirstName;
Data .MiddleInitials = ObjTbl.MiddleInitials;
Data .FkClientID = ObjTbl.FkClientID;
Data .LastName = ObjTbl.LastName;
DB.SubmitChanges();
TableClass instance = DB.GetChangeSet().Updates.OfType<TableClass>().Where(m => m.PkId == Id).First();
DB.TableClass.GetModifiedMembers(instance);
}
}

You need to check for your changes before you call SubmitChanges.
Also, in your example the line
TableClass instance = DB.GetChangeSet().Updates.OfType<TableClass>().Where(m => m.PkId == Id).First();
will throw an exception if nothing was changed, otherwise it will return the record you are amending ie, Data, so you may as well just do something like
ModifiedMemberInfo[] changes = DB.TableClass.GetModifiedMembers(Data);
If nothing has been changed, then this will return an empty array, rather than throw an exception.

Related

How to save an Id into a variable in EntityFrameworkCore and SQLite

I am very new to the Entity Framework Core and working with SQL
I have created a table called 'User' in a database and everytime I a new user is created, a new Id is also generated since it is a primary key. I want to be able save the users Id when they login, so that if they add a new workout to the workout table, then it will be saved with their Id.
I have tried:
foreach (var field in data)
{
if (context.User.Any(user => user.Name == UserName && user.Password == PassWord))
{
int UserID = context.User.Any(user => user.Id = UserID);
}
But I still don't exactly know how the queries work
Please help me.
"Any" returns a boolean.
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any?view=net-6.0
So the .Any in your first statement is "technically ok", but you end up doing 2 checks to find the object (your "User")....and your second Any doesn't seem correct.
See the below:
https://www.learnentityframeworkcore.com/dbset#retrieving-an-entity
So you might want to try FirstOrDefault
(the below is a modified version that comes from the "learnentityframeworkcore" website above.
int primaryKey = 0;
using (SampleContext context = new SampleContext())
{
Author foundAuthor = context.Authors.FirstOrDefault(a => a.LastName == "Shakespeare");
if (null != foundAuthor)
{
primaryKey = foundAuthor.AuthorKey;
}
}
You can also try
SingleOrDefault
where the "Single" will throw an exception if more than 1 row is found. (Your code as-is has a pitfall of finding more than one match....maybe you have a unique-constraint on username...but it isn't shown here.
Sidenotes:
your "for" loop .. looks very dangerous. how many times are you checking for the matching userid?
keeping passwords as plain text in your database is a HORRIBLE/DANGEROUS/SECURITY-ISSUE.
Don't use .Any, use .FirstOrDefault and check for null.
If your user is not null, you may access the Id property

Entity Framework - explain my code

Is this a correct understanding of what this code does - and is it the correct way to update a row which has a URLPath of url so that the IsInProcessing column is true?
I haven't actually tried this code yet. Before I do, I want to try and understand it! It is pieced together from various sources.
The code:
using(var db = new DamoclesEntities())
{
var urls = db.URLS;
var result = urls.FirstOrDefault(u => u.URLPath == url);
result.IsInProcessingQueue = true;
db.SaveChanges();
}
What I think is happening here is within the using I am instantiating the DamoclesEntities() class as var db.
I then instantiate the db.URLS (class / table) to the var urls.
I then find the first row where the URLPath (column) contains url, and that row is assigned to result.
I change that row's IsInProcessingQueue (column value) to true;
Finally, I save the changes to the database.
it is almost correct, but keep in mind, that FirstOrDefault will return null value in case if there is no rows found by specified criteria - URLPath == url.
So in this case next row will produce NullReferenceException.
Just add check of result for a null and do result.IsInProcessingQueue = true;db.SaveChanges(); only if result != null

EJDB C# Binding

I'm having some trouble with the C# Binding for EJDB.
It's propably just an understanding issue.
Well I want to use EJDB to store some very basic Data. This Data shall be available whenever I start my program. (persistent)
I get no error running the code. It skips over the foreach at the end as the query.Find() returns nothing.
If you have a look at the comments, you see i do a query on "myCollection" twice. Once after I inserted data and once later in the second method.
The first count returns 1 and the second count returns 0. Indicating that there must be some datawipe between those two methods. My guess is the Dispose method, though if i do not call this the db does not get closed and i get exceptions when i try to open it again.
Any help would be greatly appreciated. Is EJDB only for Runtime data? Or do i have to save the DB somehow? Like a commit. Or do I close the DB wrong?
Now my code looks kinda like that:
static public Data createNewData(Data myData)
{
var myDB = new EJDB("MyDB", EJDB.DEFAULT_OPEN_MODE | EJDB.JBOTRUNC);
myDB.ThrowExceptionOnFail = true;
var data = BSONDocument.ValueOf(new
{
name = myData.Name,
guiName = myData.GuiName
});
myDB.Save("myCollection", data);
//update ID
myData.m_ID = data["_id"].ToString();
//returns 1, => it worked
int count = myDB.CreateQueryFor("myCollection").Count();
//close the DB (as in the example, maybe thats the error? but then how to close the DB?)
myDB.Dispose();
//now calling the second method where the DB is empty again
AllData.updateData();
return myData;
}
static internal void updateData()
{
var myDB = new EJDB("MyDB", EJDB.DEFAULT_OPEN_MODE | EJDB.JBOTRUNC);
myDB.ThrowExceptionOnFail = true;
//just for testing
//returns 0 DB seems to be empty, but i just stored the data in the previous method?!
int count = myDB.CreateQueryFor("myCollection").Count();
//get all data stored in myCollection
var query = myDB.CreateQueryFor("myCollection");
//this always finds nothing. the db seems to be empty
using (var cur = query.Find())
{
//this foreach gets skipped as there is cur is empty
foreach (var e in cur)
{
BSONDocument rdoc = e.ToBSONDocument();
Data newData = Data.createNewDataFromBSONDocument(rdoc);
AllData.Add(newData);
}
}
myDB.Dispose();
query.Dispose();
}
Oops i found the error. shame on me One shall not copy paste from the example without thinking.
It was the Option EJDB.JBOTRUNC when opening the DB which just deletes all previous Data...

C# How do I remove values for a specific item in the database

I'm having problems deleting from my database
I have the following
Member thisMember = db.Members.First(m => m.MemberID == member.MemberID);
db.Members.Remove(thisMember.Name);
db.Members.Remove(thisMember.LastName);
But I keep getting an invalid arguments error. Can someone assist me?
Thanks!
db.Members.Remove is used to remove whole record (row/object) from data source. So you can remove whole member like this:
db.Member.Remove(thisMember);
If you want to set values of thisMember then you can do it like this:
Member thisMember = db.Members.First(m => m.MemberID == member.MemberID);
thisMember.Name = "";
// provided that it allows null value
thisMember.LastName = null;
// save changes in data source
db.SaveChanges();

LINQ to SharePoint 2010 getting error "All new entities within an object graph must be added/attached before changes are submitted."

I've been having a problem for some time, and I've exhausted all means of figuring this out for myself.
I have 2 lists in a MS Sharepoint 2010 environment that are holding personal physician data for a medical group...nothing special just mainly text fields and a few lookup choice fields.
I am trying to write a program that will migrate the data over from List A to List B. I am using LINQ to Sharepoint to accomplish this. Everything compiles just fine, but when it runs and hits the SubmitChanges() method, I get a runtime error that states:
"All new entities within an object graph must be added/attached before changes are submitted."
this issue must be outside of my realm of C# knowledge because I simply cannot find the solution for it. The problem is DEFINITELY stemming from the fact that some of the columns are of type "Lookup", because when I create a new "Physician" entity in my LINQ query, if I comment out the fields that deal with the lookup columns, everything runs perfectly.
With the lookup columns included, if I debug and hit breakpoints before the SubmitChanges() method, I can look at the new "Physician" entities created from the old list and the fields, including data from the lookup columns, looks good, the data is in there the way I want it to be, it just flakes out whenever it tries to actually update the new list with the new entities.
I have tried several methods of working around this error, all to no avail. In particular, I have tried created a brand new EntityList list and calling the Attach() method after each new "Physician" Entity is created, but to no avail, it just sends me around in a bunch of circles, chasing other errors such as "ID cannot be null", "Cannot insert entities that have been deleted" etc.,
I am no farther now than when I first got this error and any help that anyone can offer would certainly be appreciated.
Here is my code:
using (ProviderDataContext ctx = new ProviderDataContext("http://dev"))
{
SPSite sitecollection = new SPSite("http://dev");
SPWeb web = sitecollection.OpenWeb();
SPList theOldList = web.Lists.TryGetList("OldList_Physicians");
//Create new Physician entities.
foreach(SPListItem l in theOldList.Items)
{
PhysiciansItem p = new PhysiciansItem()
{
FirstName = (String)l["First Name"],
Title = (String)l["Last Name"],
MiddleInitial = (String)l["Middle Init"],
ProviderNumber = Convert.ToInt32(l["Provider No"]),
Gender = ConvertGender(l),
UndergraduateSchool =(String)l["UG_School"],
MedicalSchool = (String)l["Med_School"],
Residency = (String)l["Residency"],
Fellowship = (String)l["Fellowship"],
Internship = (String)l["Internship"],
PhysicianType = ConvertToPhysiciantype(l),
Specialty = ConvertSpecialties(l),
InsurancesAccepted = ConvertInsurance(l),
};
ctx.Physicians.InsertOnSubmit(p);
}
ctx.SubmitChanges(); //this is where it flakes out
}
}
//Theses are conversion functions that I wrote to convert the data from the old list to the new lookup columns.
private Gender ConvertGender(SPListItem l)
{
Gender g = new Gender();
if ((String)l["Sex"] == "M")
{
g = Gender.M;
}
else g = Gender.F;
return g;
}
//Process and convert the 'Physician Type', namely the distinction between MD (Medical Doctor) and
//DO (Doctor of Osteopathic Medicine). State Regualtions require this information to be attached
//to a physician's profile.
private ProviderTypesItem ConvertToPhysiciantype(SPListItem l)
{
ProviderTypesItem p = new ProviderTypesItem();
p.Title = (String)l["Provider_Title:Title"];
p.Intials = (String)l["Provider_Title"];
return p;
}
//Process and convert current Specialty and SubSpecialty data into the single multi-choice lookup column
private EntitySet<Item> ConvertSpecialties(SPListItem l)
{
EntitySet<Item> theEntityList = new EntitySet<Item>();
Item i = new Item();
i.Title = (String)l["Provider Specialty"];
theEntityList.Add(i);
if ((String)l["Provider SubSpecialty"] != null)
{
Item theSubSpecialty = new Item();
theSubSpecialty.Title = (String)l["Provider SubSpecialty"];
theEntityList.Add(theSubSpecialty);
}
return theEntityList;
}
//Process and add insurance accepted.
//Note this is a conversion from 3 boolean columns in the SP Environment to a multi-select enabled checkbox
//list.
private EntitySet<Item> ConvertInsurance(SPListItem l)
{
EntitySet<Item> theEntityList = new EntitySet<Item>();
if ((bool)l["TennCare"] == true)
{
Item TenncareItem = new Item();
TenncareItem.Title = "TennCare";
theEntityList.Add(TenncareItem);
}
if ((bool)l["Medicare"] == true)
{
Item MedicareItem = new Item();
MedicareItem.Title = "Medicare";
theEntityList.Add(MedicareItem);
}
if ((bool)l["Commercial"] == true)
{
Item CommercialItem = new Item();
CommercialItem.Title = "Commercial";
theEntityList.Add(CommercialItem);
}
return theEntityList;
}
}
So this may not be the answer you're looking for, but it's what's worked for me in the past. I've found that updating lookup fields using Linq to Sharepoint to be quite frustrating. It frequently doesn't work, or doesn't work efficiently (forcing me to query an item by ID just to set the lookup value).
You can set up the entity so that it has an int property for the lookup id (for each lookup field) and a string property for the lookup value. If, when you generate the entities using SPMetal, you don't generate the list that is being looked up then it will do this on it's own. What I like to do is (using your entity as an example)
Generate the entity for just that one list (Physicians) in some temporary folder
Pull out the properties for lookup id & value (there will also be private backing fields that need to come along for the ride too) for each of the lookups (or the ones that I'm interested in)
Create a partial class file for Physicians in my actual project file, so that regenerating the entire SPMetal file normally (without restricting to just that list) doesn't overwrite changes
Paste the lookup id & value properties in this partial Physicians class.
Now you will have 3 properties for each lookup field. For example, for PhysicianType there will be:
PhysicianType, which is the one that is currently there. This is great when querying data, as you can perform joins and such very easily.
PhysicianTypeId which can be occasionally useful for queries if you only need ID as it makes it a bit simpler, but mostly I use it whenever setting the value. To set a lookup field you only need to set the ID. This is easy, and has a good track record of actually working (correctly) in my experiences.
PhysicianTypeValue which could be useful when performing queries if you just need the lookup value, as a string (meaning it will be the raw value, rather than something which is already parsed if it's a multivalued field, or a user field, etc. Sometimes I'd rather parse it myself, or maybe just see what the underlying value is when doing development. Even if you don't use it and use the first property, I often bring it along for the ride since I'm already doing most of the work to bring the PhysicianTypeId field over.
It seems a bit hacky, and contrary to the general design of linq-to-SharePoint. I agree, but it also has the advantage of actually working, and not actually being all that hard (once you get the rhythm of it down and learn what exactly needs to be copied over to move the properties from one file to another).

Categories