I have been searching for an answer to this for a couple of days now and I'm completely stuck. I am assuming its just that I am not looking for the right thing as I'm sure the solution is simple and it is just something I have done wrong.
For some reason when I try to get data from the database using Entity Framework like this code below, nothing happens. When I stepped through the code I found that it was getting to the line that gets the data from the database and then just jumped out of the function, no errors, nothing, the application just carries on running, but I don't get my data.
private void CreateKitWindow_Loaded(object sender, RoutedEventArgs e)
{
string kitID = "";
using (MyContext foo = new MyContext())
{
foo.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
LaminationKit theKit = foo.Lamination_Kit.OrderByDescending(x => x.KitNumber).First();
kitID = theKit.KitNumber;
}
kitNumber.Content = kitID;
}
I found out about the database log line here on Stack Overflow and added it and inspected the results.
Opened connection at 2/12/2015 2:26:22 p.m. +13:00
SELECT TOP (1)
[Extent1].[UID] AS [UID],
[Extent1].[KitNumber] AS [KitNumber],
[Extent1].[dateCreated] AS [dateCreated],
[Extent1].[lastTransaction] AS [lastTransaction],
[Extent1].[daysLeft] AS [daysLeft],
[Extent1].[hoursLeft] AS [hoursLeft],
[Extent1].[minsLeft] AS [minsLeft],
[Extent1].[jobNo] AS [jobNo],
[Extent1].[assemblyNo] AS [assemblyNo],
[Extent1].[storageLocation] AS [storageLocation],
[Extent1].[jobName] AS [jobName],
[Extent1].[jobDescription] AS [jobDescription],
[Extent1].[mouldNumber] AS [mouldNumber],
[Extent1].[targetJob] AS [targetJob],
[Extent1].[targetAssembly] AS [targetAssembly],
[Extent1].[targetLine] AS [targetLine],
[Extent1].[dateFrozen] AS [dateFrozen],
[Extent1].[dateThawed] AS [dateThawed],
[Extent1].[cookDate] AS [cookDate]
FROM [dbo].[LaminationKit] AS [Extent1]
ORDER BY [Extent1].[KitNumber] DESC
-- Executing at 2/12/2015 2:26:22 p.m. +13:00
-- Completed in 5 ms with result: SqlDataReader
Exception thrown: 'System.InvalidOperationException' in EntityFramework.dll
Closed connection at 2/12/2015 2:26:22 p.m. +13:00
Can anyone tell me what is happening here? The query is valid and according to this, completed successfully, but then throws an exception.
I pasted that exact query into SQL server management studio and it runs fine and does exactly what I want.
Here is the context if that helps (extra stuff removed)
class MyContext : DbContext
{
public MyContext() : base("Password=xxxxxxx;Persist Security Info=True;User ID=xxxxxxxx;Data Source=ssnzsql02;Packet Size=4096;Initial Catalog=SS_Outlife_E10")
{
}
public DbSet<LaminationKit> Lamination_Kit { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
The other thing is that I can get data using the longer
var foo = from item in context.table
where item.this == something
Orderby item.that
select item
foreach(var t in foo)
{
//loop through and do stuff
}
Method just fine, but I don't want to do this in every case.
The issue is not just on this table, its happened on lots of different tables in the database.
Thank you cFrozenDeath and FizzBuzz, i don't know why i didn't think to try this in the first place. (maybe because no actual crash or break was happening during run time)
I threw a try / catch round it to see if it would catch it and i get this message
The 'dateFrozen' property on 'LaminationKit' could not be set to a 'null' value. You must set this property to a non-null value of type 'System.DateTime'.
So turns out it was super simple and i just derped, i need to make sure that i set my data types to nullable for table fields that allow null values #EpicFacepalm
changing
public DateTime dateFrozen { get; set; }
to
public Nullable<DateTime> dateFrozen { get; set; }
solved it.
Now to go through everything and fix all the others.
Related
I've been trying to get a EntityFramework solution working for an upcoming project connecting to a Postgres database, and a majority of the work has been completed. However, when trying to add/update entities in bulk, I've been having some issues and I'm unsure as to whether the error below is masking the actual error with my process:
Database operation expected to affect 1 row(s) but actually affected 0 row(s).
Data may have been modified or deleted since entities were loaded.
See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
I am using the design time context factory pattern to allow my Azure function app to call this, this is my current implementation:
public class ContextFactory : IDesignTimeDbContextFactory<Context>
{
public Context CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<Context>();
optionsBuilder.UseNpgsql("{ConnectionString}");
optionsBuilder.EnableDetailedErrors();
optionsBuilder.EnableSensitiveDataLogging();
return new Context(optionsBuilder.Options);
}
}
And my current addition to the services of the function app via Startup.cs:
builder.Services.AddDbContext<ESRContext>(options =>
options.UseNpgsql(Environment.GetEnvironmentVariable("PostgreDBConnectionString")));
There is currently nothing within the table that I'm trying to work with when trying to call the context.SaveChanges() method. Below is my entity model that I've been using:
public class Record
{
public int UserId { get; set; }
public int CourseID { get; set; }
[ConcurrencyCheck]
public int CourseSessionID { get; set; }
public string Code { get; set; }
[ConcurrencyCheck]
public DateTime DateFrom { get; set; }
[ConcurrencyCheck]
public DateTime DateTo { get; set; }
}
(Excuse the formatting, couldn't quite get it to line up!)
I'm working through a file that maps to this entity by row, and adding/updating based on whether this row exists in context or not. For example:
If rows within the same file first add a completion of a course to the context using Context.Records.Add(), and then subsequent rows aim to update it for the user/course combination further down in the file by first getting the entity from the context, modifying that entity with the new properties, and then saving it back using Context.Records.Update(record). Firstly, is this the correct way of doing it? I'll add a snippet of code that follows the basic flow that I've implemented:
try
{
//File rows based through as Records
foreach (var record in fileRecords)
{
var existingRecord = GetRecord(int.Parse(record.UserId), int.Parse(record.CourseId));
if (existingRecord != null)
{
if (existingRecord.DateFrom < DateTime.ParseExact(record.DateFrom, "yyyyMMdd", CultureInfo.InvariantCulture))
{
UpdateRecord(existingRecord, record);
}
}
else
{
_logger.LogInformation(
"User with userId of {userId} on competence {courseId} could not be found in reference store. Adding.",
record.userId, record.courseId
);
var addedRecord = new Data.Entities.Record
{
UserId = int.Parse(record.UserId),
CourseSessionId = int.Parse(record.CourseSessionId),
Code = code,
CourseId = int.Parse(record.CourseId),
DateFrom = string.IsNullOrWhiteSpace(record.DateFrom) ? DateTime.MinValue : DateTime.ParseExact(record.DateFrom, "yyyyMMdd", CultureInfo.InvariantCulture),
DateTo = string.IsNullOrWhiteSpace(record.DateTo) ? DateTime.MinValue : DateTime.ParseExact(record.DateTo, "yyyyMMdd", CultureInfo.InvariantCulture)
};
_context.Records.Add(addedRecord);
}
}
_context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
var record = (Data.Entities.Record)entry.Entity;
_logger.LogInformation("Concurrency issue found: \n" +
"UserId {userId} \n" +
"CourseId {courseId} \n" +
"CourseSessionId {courseSessionId} \n" +
"DateFrom: {dateFrom} \n" +
"DateTo: {dateTo}",
record.UserId,
record.CourseId,
record.CourseSessionId,
record.DateFrom,
record.DateTo
);
}
}
private void UpdateRecord(Data.Entities.Record existingRecord, FileRecord updatedRecord)
{
existingRecord.CourseSessionId = int.Parse(updatedRecord.CourseSessionId);
existingRecord.DateFrom = string.IsNullOrWhiteSpace(updatedRecord.DateFrom) ? DateTime.MinValue : DateTime.ParseExact(updatedRecord.DateFrom, "yyyyMMdd", CultureInfo.InvariantCulture);
existingRecord.DateTo = string.IsNullOrWhiteSpace(updatedRecord.DateTo) ? DateTime.MinValue : DateTime.ParseExact(updatedRecord.DateTo, "yyyyMMdd", CultureInfo.InvariantCulture);
_context.Records.Update(existingRecord);
}
private Data.Entities.Record GetRecord(int userId, int courseId)
{
var returnedObject = _context.Records.SingleOrDefault(er => er.UserId == userId && er.CourseId == courseId);
return returnedObject;
}
This question has probably gone all over the place with what I'm trying to ask, so apologies! Essentially, I am receiving this error noted above, and I'm unsure as to whether I am missing any best practices or something else, as the error seems really generic and doesn't contain an InnerException when caught.
I will monitor and update this question based on comments received. Hope you guys can help with this issue!
Glad that #JakeRoper could able to solve the issue. Thank you #jdweng for your suggestions that helped the op to fix the issue. Posting this on behalf of your discussion so that it could help other community members.
You are receiving the below error message because you are using both the update() and savechanges() which causes concurrency conflicts. You can use either of one of the functions which can update the record.
Database operation expected to affect 1 row(s) but actually affected 0 row(s).
Data may have been modified or deleted since entities were loaded.
See http://go.microsoft.com/fwlink/?LinkId=527962 for information on >understanding and handling optimistic concurrency exceptions.
If the error still persists the other approach is that the DbUpdateConcurrencyException should be caught during SaveChanges. For more information related to concurrency exceptions, you can refer to Handling Concurrency Conflicts.
i´m using EF6.
After i clear a tabel and i want to add a new entry to that table i get the following error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded
The code for deleting the databasetable:
public void ResetStatistics() {
_lisDatabase.Database.ExecuteSqlCommand("TRUNCATE TABLE Sortedtubes");
_lisDatabase.sortedtubes.Local.Clear();
}
After that i want to add a new entry to that table with the following code:
Sortedtubes tube = new Sortedtubes();
tube.Time = time;
tube.Milliseconds = time.Millisecond.ToString();
tube.Barcode = barcode;
tube.Tubetype = tubeType;
tube.Target = target;
tube.Materialcode = materialCode;
try {
_lisDatabase.sortedtubes.Add(tube);
_lisDatabase.SaveChanges(); // Error appears here
} catch (DbUpdateConcurrencyException ex) {
// maybe do something here?
}
I tryed the sugestions on the EF documentation with no luck:
https://msdn.microsoft.com/en-us/data/jj592904
EDIT
The problem seems to be the Clear() method (_lisDatabase.sortedtubes.Local.Clear();). After i execute this method the error appears after the next SaveChanges().
So maybe there is an other way to handle this? I have a GridView in my application witch is bind to the sortedtubes entity and i clear it so that the GridView is also cleared, when i truncat the table.
It seems to me that your problem lies in trying to truncate the table and manually clearing your local version of the DbSet. You should just change your EF entities and save them, then those changes are reflected in the database.
This should work:
_lisDatabase.SortedTubes.RemoveRange(_lisDatabase.SortedTubes);
_lisDatabase.SortedTubes.Add(new SortedTube());
_lisDatabase.SaveChanges();
Alternatively, try this:
https://stackoverflow.com/a/10450893/5392513
I suspected that you retrieve the entiries from database with same context by tracking before Truncate the table and when you apply the SaveChanges the EF is trying to delete already deleted records by Truncate. So, usual way to perform it creating a new instance from context and apply actions. It is not good idea to make long database processes with same context. So, in your case if you want to truncate table and use the same context to add new entries later you should detach all tracked entries after truncate action.
public void ResetStatistics()
{
_lisDatabase.Database.ExecuteSqlCommand("TRUNCATE TABLE Sortedtubes");
_lisDatabase.sortedtubes.Local.Clear();
foreach (var entry in _lisDatabase.ChangeTracker.Entries<Sortedtubes>())
{
_lisDatabase.Entry(entry).State = EntityState.Detached;
}
}
Also, if it is possible use .AsNoTracking in your queries before Truncate the table and no need to detach entries manually.
So.. finaly i think i got a solution.
My reset method looks like this now:
public void ResetStatistics() {
_lisDatabase.sortedtubes.RemoveRange(_lisDatabase.sortedtubes);
_lisDatabase.SaveChanges();
}
And my add stays the same:
_lisDatabase.sortedtubes.Add(tube);
_lisDatabase.SaveChanges();
but the "big" change was in my Sortedtubes entity. I changed the type of Time from DateTime to a normal String
from:
[Key]
[Column(Order = 1)]
public DateTime? Time { get; set; }
to:
[StringLength(45)]
public string Time { get; set; }
The problem seems to be the Type of the Time property of the Sortedtubes Entity. But i don`t know why.
If anyone wants to explain me this case?
Thanks to all for your help.
I have this class:
public class PlaylistMessageBindingModel
{
//Other non-important fields
public Decimal Duration { get; set; }
}
I am instantiating an object of this class and read values out of a database with a data reader:
while (innerReader.Read())
{
var playlistMsg = new PlaylistMessageBindingModel();
playlistMsg.Duration = (Decimal)reader["size_time"];
}
But when it hits the .Duration line of code, it throws an Exception:
An exception of type 'System.Exception' occurred in MyDll.dll but was not handled in user code
Additional information: size_time
The value column in the database is decimal(6, 3). I'm guessing it might have to do with the fact that the value coming out of the database is 0.000, but if that is the case, I'm not sure how to deal with that. I'd appreciate any observations.
Have you tried this?
while (innerReader.Read())
{
var playlistMsg = new PlaylistMessageBindingModel();
playlistMsg.Duration = reader.GetDecimal["size_time"];
}
Also very useful SQL Server Data Type Mappings
This is what happens when you stare at your own code for too long...
I failed to notice a subtle difference in my reader objects. Above this section of code, I have instantiated a reader called reader. Further down the code, I instantiated innerReader. So when I was trying to set the duration, I have while (innerReader.Read()) and inside that code block I'm trying playlistMsg.Duration = (Decimal)reader["size_time"]; but it should be (Decimal)innerReader["size_time"]. After changing the code, I got my intended result.
I'm developing a C# ASP.NET application, in which i'm retrieving some data from the database, throwing in a form, and when i click on Save, i want it to save my changes in the database.
I'm using Linq to SQL. The code below, at the end, call the method ClienteBusiness.SalvarAlteracoes(cliente), which by the way, only calls the ClienteData.SalvarAlteracoes(cliente) method.
protected void Salvar()
{
TB_CLIENTE_CLI cliente = new TB_CLIENTE_CLI();
int idEstado = 0;
int idCidade = 0;
if (!Int32.TryParse(ddlEstado.SelectedValue, out idEstado))
{
return;
}
if (!Int32.TryParse(Request.Form[ddlCidade.UniqueID], out idCidade))
{
return;
}
cliente.TXT_RAZAOSOCIAL_CLI = txtRazaoSocial.Text;
cliente.TXT_NOMEFANTASIA_CLI = txtNomeFantasia.Text;
cliente.TXT_CNPJ_CLI = txtCNPJ.Text;
cliente.TXT_CEP_CLI = txtCEP.Text;
/*e os demais campos*/
//Se a tela for de edição, altera o valor do ID para o cliente correspondente.
cliente.ID_CLIENTE_CLI = this.IdCliente;
ClienteBusiness.SalvarAlteracoes(cliente);
HTMLHelper.jsAlertAndRedirect(this, "Salvo com sucesso!", ResolveUrl("~/Pages/ClientePage.aspx"));
}
The method which save the changes is described below:
public static Int32 SalvarAlteracoes(TB_CLIENTE_CLI cliente)
{
using (PlanoTesteDataContext context = DataContext.ObterConexao())
{
if (cliente.ID_CLIENTE_CLI == 0)
{
context.TB_CLIENTE_CLIs.InsertOnSubmit(cliente);
}
else
{
context.TB_CLIENTE_CLIs.Attach(cliente, true);
}
context.SubmitChanges();
} return cliente.ID_CLIENTE_CLI;
}
On the line context.TB_CLIENTE_CLIs.Attach(cliente, true); i'm receiving a System.InvalidOperationException: An entity can only be attached as modified without original state if it declares a version member or does not have an update check policy.
I've already checked the UpdateChecks and they are set to Never.
What can I do? Thanks and sorry for the bad english.
This should work:
else
{
context.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, cliente);
context.TB_CLIENTE_CLIs.Attach(cliente);
}
This Refresh overload will keep the changes made by the user,it compares the modified entity with the original values from the database, detects the difference and marks the entity as modified and the call to SubmitChanges applies the update to the database.
You may very well run into trouble using Linq2SQL with disconnected entities. EF is a more suited solution to handle this.
However, please ensure you have set all properties on the entity on UpdateCheck to NEVER. I have tested this myself and it works. If this does work it will run an UPDATE statement on every column regardless of whether it has been updated or not. Could cause a problem if you use triggers on your tables. It might be a better idea to use a Timestamp instead to track the entities so concurrency issues between multiple users can be raised.
If you try to Attach an entity from a context where the ObjectTrackingEnabled is not set to False then you will have the following exception thrown:
An unhandled exception of type 'System.NotSupportedException' occurred in System.Data.Linq.dll
Additional information: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
As an example please use the following for retrieving and reattaching an entity:
public TB_CLIENTE_CLI Get(int id)
{
using (PlanoTesteDataContext ctx = new PlanoTesteDataContext())
{
ctx.ObjectTrackingEnabled = false;
return ctx.TB_CLIENTE_CLI.SingleOrDefault(n => n.ID == id);
}
}
public void Save(TB_CLIENTE_CLI cliente)
{
using (PlanoTesteDataContext ctx = new PlanoTesteDataContext())
{
ctx.DeferredLoadingEnabled = false;
ctx.TB_CLIENTE_CLI.Attach(cliente, true);
ctx.SubmitChanges();
}
}
You will also need to set DeferredLoadingEnabled loading to False in the Save method so that you can save down changes on the entity subsequent times after the first initial save on modification.
I have a MVC Web Application using the following approach:
public class MyController : Controller
{
public FooRepository fooRepository = new FooRepository();
public BarRepository barRepository = new BarRepository();
public ActionResult UpdateItems(int id, int range1, int range2)
{
Foo foo = fooRepository.GetItem(id);
List<Bar> bars = barRepository.GetItemsByRange(range1, range2);
// Some validation rules here...
DoSomeWork(foo, bars);
// Show confirmation / error message
}
private void DoSomeWork(Foo foo, List<Bar> bars)
{
foreach(int i = 0; i < bars.Count; i++)
{
bars[i].Prop1 = foo.Prop1; // This field is updated
bars[i].Owner = "someuser"; // This one too
bars[i].Status = BarStatus.SomeStatus; // This isn't...
}
foo.Status = FooStatus.SomeStatus; // Ok
// Calls DataContext.SubmitChanges()
fooRepository.SubmitChanges();
barRepository.SubmitChanges();
}
}
However, in some "random" cases (I see no pattern), one of the fields doesn't get updated, as noted in the comments.
It seems like LINQ isn't recognizing the field's update, so it gets excluded from the generated query.
Can anyone tell me if I'm missing something here, what could be causing it and/or how can I solve it?
Note: I don't get any Exception and can't verify this case in a development scenario.
From my experience if the error is random and you can't reproduce in development than the problem is user error.
Programming would be really hard if the .net framework or the CLR just randomly decided to do things differently.
You probably have an implicit/explicit bind exclusion floating around somewhere
[Bind(Exclude="...,Status,...")]
Just guessing of course
If Linq thinks that the Status is already BarStatus.SomeStatus, then it won't update it.
What can happen is that you find a record with the status set to this value, and then some other routine changes it, and then, if you are using your same DataContext, you will get the old value from the cached copy and hence Linq thinks that it does not need to update it.