how to find and Update record on Parse.com - c#

I'm working on c# winforms Application. I want to find and Update any specific record on parse.com.
My problem is that I find the record but I don't know how to update it.
The find code is this:
int ID = Convert.ToInt32(txtId.Text);
var FindID = (from find in ParseObject.GetQuery("DriverID")
where find.Get<Int32>("DriverID") == ID
select find);
var ID = FindID.FindAsync();

Finally its working
public async void UpdateDriverOnParse(Int32 ID)
{
var query = (from find in ParseObject.GetQuery("DriverLogin")
where find.Get<Int32>("SystemID") == ID
select find);
// Retrieve the results
IEnumerable<ParseObject> Data = await query.FindAsync();
//for updating the selected row
foreach (var row in Data)
{
row["Pin"] = Convert.ToInt32(txtPinNo.Text);
row["DriverID"] = Convert.ToInt32(txtCallSign.Text);
row["Name"] = txtFirstName.Text+" "+txtMname.Text+" "+txtLastName.Text;
await row.SaveAsync();
}
}

FindAsync returns an IEnumerable. If you just want one object you can use FirstAsync. When you have your object, update it like you would any IDictionary and then call 'await ID.SaveAsync()'

Related

Entity is incorrectly detaching from tracking EF Core

I am trying to query objects from a database, loop through them and check if a column has a value and, if it does not, create a value and assign it to that column and save it to the database. The problem I'm having is that the entity is detaching after the query so I cannot save the changes. Below is the code I am using to query and update the entity.
DateTime runTime = passedDateTime ?? DateTime.Now;
await using DiscordDatabaseContext database = new();
DateTime startOfWeek = exactlyOneWeek ? runTime.OneWeekAgo() : runTime.StartOfWeek(StartOfWeek);
//Add if not in a Weekly Playlist already and if the video was submitted after the start of the week
List<PlaylistData> pld = await database.PlaylistsAdded.Select(playlist => new PlaylistData
{
PlaylistId = playlist.PlaylistId,
WeeklyPlaylistID = playlist.WeeklyPlaylistID,
Videos = playlist.Videos.Where(
video => (video.WeeklyPlaylistItemId == null ||
video.WeeklyPlaylistItemId.Length == 0) &&
startOfWeek <= video.TimeSubmitted)
.Select(video => new VideoData
{
WeeklyPlaylistItemId = video.WeeklyPlaylistItemId,
VideoId = video.VideoId
}).ToList()
}).ToListAsync().ConfigureAwait(false);
int count = 0;
int nRows = 0;
foreach (PlaylistData playlistData in pld)
{
if (string.IsNullOrEmpty(playlistData.WeeklyPlaylistID))
{
playlistData.WeeklyPlaylistID = await YoutubeAPIs.Instance.MakeWeeklyPlaylist().ConfigureAwait(false);
}
foreach (VideoData videoData in playlistData.Videos)
{
PlaylistItem playlistItem = await YoutubeAPIs.Instance.AddToPlaylist(videoData.VideoId, playlistId: playlistData.WeeklyPlaylistID, makeNewPlaylistOnError: false).ConfigureAwait(false);
videoData.WeeklyPlaylistItemId = playlistItem.Id;
++count;
}
}
nRows += await database.SaveChangesAsync().ConfigureAwait(false);
The query works correctly, I get all relevant Playlist and Video Rows to work with, they have the right data in only the specified columns, and the query that is logged looks good, but saves do not work and calling database.Entry() on any of the Playlists or Video objects show that they are all detached. What am I doing wrong? Are collections saved a different way? Should my query be changed? Is there a setting on initialization that should be changed? (The only setting I have set on init that I feel like may affect this is .UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery) but the query logged isn't even split as far as I can see)
You work with projected objects
PlaylistData
VideoData
Projected objects does not tracked by EF core as far as I know. So the solution is to select DbSet's entity objects (mean types that specified in database.PlaylistsAdded and playlist.Videos properties) or select those objects before update and then update them.
UPDATE:
Example code for second option:
foreach (PlaylistData playlistData in pld)
{
var playlist = database.PlaylistsAdded
.Include(x=> x.Videos)
.First(x => x.PlaylistId == playlistData.playlistData);
if (string.IsNullOrEmpty(playlistData.WeeklyPlaylistID))
{
playlist.WeeklyPlaylistID = await YoutubeAPIs.Instance.MakeWeeklyPlaylist().ConfigureAwait(false);
}
foreach (VideoData videoData in playlistData.Videos)
{
var video = playlist.Videos.First(x=> x.VideoId == videoData.VideoId);
PlaylistItem playlistItem = await YoutubeAPIs.Instance.AddToPlaylist(videoData.VideoId, playlistId: playlistData.WeeklyPlaylistID, makeNewPlaylistOnError: false).ConfigureAwait(false);
video.WeeklyPlaylistItemId = playlistItem.Id;
++count;
}
}
NOTICE: this would produce double select's so first option is more preferred

How to convert SQLQuery to SortedList through EF6

I have an Entity Framework 6 class called Materials, which is reflected in my database as a table with the same name. Using a parent parameter, I need to return a sorted list of materials from a SQL Query, so that I can later check that edits the user makes do not affect the order. My SQL is a stored procedure that looks like this:
CREATE PROC [dbo].[GET_SortedMaterials](#FinishedGoodCode VARCHAR(50))
AS
SELECT
ROW_NUMBER() OVER (ORDER BY Component.Percentage_of_Parent DESC,Material.Material) AS _sortField
,Material.*
FROM
Components AS Component
INNER JOIN Materials AS Material ON Component.Child_Material = Material.Material
WHERE
Component.Parent_Code = #FinishedGoodCode
ORDER BY
Component.Percentage_of_Parent DESC
,Material.Material
As you can see, the orderby field is not included in the Material. For this reason, I felt I could not return just a set of Material objects and still keep the sorting - I have performed the ordering in SQL and added the _sortField (I think that field may be a bad idea).
My C# code to read the SQL looks like this:
public async Task<SortedList<int, Materials>> GET_SortedMaterials(IProgress<Report> progress, string finishedGoodCode)
{
try
{
var report = new Report { Message = "Retrieving Sorted Materials", NewLine = true, StatusCode = Enums.StatusCode.Working };
progress.Report(report);
using (var context = new DBContext())
{
var ingredientList = await context.Database.SqlQuery<(int _sortField,Materials mat)>("[app].[GET_Customers]").ToListAsync();
var sorted = new SortedList<int, Raw_Materials>();
foreach (var (_sortField, mat) in ingredientList.OrderBy(x=>x._sortField))
{
sorted.Add(_sortField, mat);
}
return sorted;
}
}
catch (Exception ex)
{ [EXCLUDED CODE]
}
}
When the code executes, I get the correct number of rows returned, but I do not get a Sorted list where the Key corresponds to the _sortField value and the Value to the Material value. I have tried various different versions of basically the same code and I cannot get the script to return a list of materials with information about their sorting, instead, the conversion to EF class fails entirely and I only get null values back:
Any advice about how to return a sorted list from SQL and maintain the sorting in C#, when the sort field is not in the return values would be very gratefully received.
use
var ingredientList = await context.Database.SqlQuery<Materials>("[app].[GET_Customers]").Select((mat, _sortField) => (_sortField, mat)).ToDictionary(x => x._sortField, x => x.mat);
or if you want async load use
var ingredientList = await context.Database.SqlQuery<Materials>("[app].[GET_Customers]").ToListAsync().Result.Select((mat, _sortField) => (_sortField, mat)).ToDictionary(x => x._sortField, x => x.mat);
full code
public async Task<SortedList<int, Materials>> GET_SortedMaterials(IProgress<Report> progress, string finishedGoodCode)
{
try
{
var report = new Report { Message = "Retrieving Sorted Materials", NewLine = true, StatusCode = Enums.StatusCode.Working };
progress.Report(report);
using (var context = new DBContext())
{
var ingredientList = await context.Database.SqlQuery<Materials>("[app].[GET_Customers]").ToListAsync().Result.Select((mat, _sortField) => (_sortField, mat)).ToDictionary(x => x._sortField, x => x.mat);
var sorted = new SortedList<int, Raw_Materials>();
foreach (var item in ingredientList.OrderBy(x => x.Key))
{
sorted.Add(item.Key, item.Value);
}
return sorted;
}
}
catch (Exception ex)
{
[EXCLUDED CODE]
}
}

Adding to or updating an entity in a foreach loop takes too long time before calling SaveChanges()?

I have this method that saves an entity with its related items (many-to-many relationship),
private static void Save<T>(TbCommonHistoryLog log, List<T> lstDetails) where T : IHasSerial
{
foreach (var item in lstDetails.OrderBy(x => x.Serial))
{
var ser = SerializeObject(item);
var record = oContext.TbHistoryLog_Lists.FirstOrDefault(x => x.ListObjectJson == ser);
if (record == null) //add new list item
{
TbCommonHistoryLog_Lists listObject = new TbCommonHistoryLog_Lists()
{
ListObjectJson = SerializeObject(item)
};
var details = new TbCommonHistoryLogDetails { TbHistoryLog = log, TbHistoryLog_Lists = listObject };
oContext.TbHistoryLogDetails.Add(details);
}
else //attach an existing list item
{
var o = oContext.TbHistoryLog_Lists.Find(record.Id);
oContext.TbHistoryLog_Lists.Attach(o);
var details = new TbCommonHistoryLogDetails { TbHistoryLog = log, TbHistoryLog_Lists = o };
oContext.TbHistoryLogDetails.Add(details);
}
}
oContext.BulkSaveChanges();
}
I have two tables: TbCommonHistoryLog, TbCommonHistoryLog_Lists, that are in many to many relationship, the joining table is TbCommonHistoryLogDetails,
What I'm doing here is an auditing for master-detail models, all audits are serialized to JSON in DB, I save the head object in the TbCommonHistoryLog table, and every list item in the TbHistoryLog_Lists table, in the mthod above I check if the list item is already exists in the database or not to avoid duplicating.
but this process takes more than 15 seconds which is a very long time, I can't figure out what am I doing wrong here.. please help?
For every single item in collection you're querying database. My suggestion is to save records in var, then ask the variable if the item is in database.
var databaseRecords = oContext.TbHistoryLog_Lists.ToList();
Then in the loop:
var record = databaseRecords.FirstOrDefault(x => x.ListObjectJson == ser);

Iterating over two lists in c#

So i have a function that gets a list of students from a web service and also query the localdb for all the students in there. the data is placed in two different list. So i want to check to see if a new student already exists in the localdb List. if it does, update it and it if doesn't then add it. i unable to get it working . I am trying to perform this using LINQ, but i can't seem to get it working right. My LINQ skills are amateurish at best.
public async Task GetStudents()
{
String controllerName = "Students";
List<Students> newStudentData = await RunGetAsync<Students>(controllerName);
// get all the service types that already exists in the localStudent Db
List<Students> currentStudentData = db.Studentss.ToList();
foreach (Students existingStudents in currentStudentData)
{
foreach (Students newStudents in newStudentData)
{
IEnumerable<Students> selectStudents = from student in newStudentData // check if Students exist in the database
where student.Id == existingStudents.Id
select student;
if (selectStudents == null) // didn't find it, then add it
{
db.Students.Add(newStudents);
}
if (selectStudents != null) // found it , then update the informations
{
Students updatedStudents = new Students();
foreach (var field in selectStudents)
{
updatedStudents.FName = field.FName;
updatedStudents.LName = field.LName;
updatedStudents.ZipCode = field.ZipCode;
updatedStudents.AccessCode = field.AccessCode;
}
db.Entry(updatedStudents).State = System.Data.Entity.EntityState.Modified;
}
}
}
db.SaveChanges();
}
Thank you very much for your help.
you're looping more than you need :
foreach (Students newStudents in newStudentData)
{
var student = currentStudentData.FirstOrDefault(s => s.Id == newStudents.Id);
if(student == null)
{
//add
}
else
{
//update
}
}
with FirstOrDefault you can find out if it exists and get a reference to it at the same time, if it does.
You could use Intersect and Except like below:
//Find students that already exist to update
var updateStudents = currentStudentData.Intersect(newStudentData);
//Find new students to add
var addStudents = newStudentData.Except(currentStudentData);

Do not find DeleteOnSubmit method

Im want to delete rows from a table that in my data base.
i have the member
private static WeightScaleEntities Weight = new Weight();
this member contains my database. in the data base i have table: User_Activity.
I want to delete rows from user activity by given i_UserActivityId, as follow:
//Get the rows for delete
var deleteUserActivities = from details in Weight.User_Activity
where details.Id == i_UserActivityId
select details;
Now i want to delete this rows, so i tried to do:
foreach (var item in deleteUserActivities)
{
m_WeightScaleEntities.User_Activity.*
}
and i dont get the method DeleteOnSubmit!
Why?
there is another option???
User_Activity.*: is that a typo?
What I think you want is:
foreach (var item in deleteUserActivities)
{
Weight.DeleteObject(item);
}
And then SaveChanges() on the object context.
BTW, a static object context is not a good idea. You should carefully control the life cycle of object contexts.
There is more than one way to execute deletion in Entity Framework,
You must take into account what are the values that you want to delete? one Row or more.
when you need to delete on Row from table we can use these ways:
// first way
using (WeightScaleEntities db = new WeightScaleEntities())
{
var deleteUserActivities = from details in db.User_Activity
where details.Id == i_UserActivityId
select details;
if (deleteUserActivities.Count() > 0)
{
db.deleteUserActivities.Remove(deleteUserActivities.First());
db.SaveChanges();
}
}
this line deleteUserActivities.Count()>0 to check if you have result in the Query or not.
and this deleteUserActivities.First() if the query return set of rows delete the first. "to make the process more secure if you don't know about the data in the table"
// second way
using (WeightScaleEntities db = new WeightScaleEntities())
{
var deleteUserActivities = (from details in db.User_Activity
where details.Id == i_UserActivityId
select details).SingleOrDefault();
if (deleteUserActivities != null)
{
db.User_Activity.Remove(deleteUserActivities);
// or use this line
//db.Entry(deleteUserActivities).State = System.Data.Entity.EntityState.Deleted;
db.SaveChanges();
}
}
You can also use Single or SingleOrDefault to get a single object. Single or SingleOrDefault will throw an exception, if the result contains more than one element. Use Single or SingleOrDefault where you are sure that the result would contain only one element. If the result has multiple elements then there must be some problem.
Also, if you need to remove one or multi rows use this way:
using (WeightScaleEntities db = new WeightScaleEntities())
{
var deleteUserActivities = (from details in db.User_Activity
where details.Id == i_UserActivityId
select details).ToList<User_Activity>(); //<User_Activity> her name of your DbSet
foreach(deleteObject in deleteUserActivities)
{
db.Entry(deleteObject).State = System.Data.Entity.EntityState.Deleted;
}
db.SaveChanges();
}
Best Regards
and sorry about English language.
using(WeightScaleEntities db=new WeightScaleEntities())
{
var deleteUserActivities = from details in db.User_Activity
where details.Id == i_UserActivityId
select details;
if (deleteUserActivities.Count()>0)
{
db.deleteUserActivities.Remove(deleteUserActivities.First());
db.SaveChanges();
}
}

Categories

Resources