EF EntityState.Modified Try Catch Issue - c#

I have a code like this:
try
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
catch (Exception ex)
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
And Entity:
[StringLength(5)]
public string Name { get; set; }
If the Name String more than 5 it would be error and catch the exception ,but when I add a log then save ,the exception from SaveChange(); still remains,how should I do?(Can't change the schema)

the exception from SaveChange(); still remains
Well, if this throws an exception:
database.SaveChanges();
Then there's a pretty good chance that this will also throw an exception:
database.SaveChanges();
Basically, in your catch block you shouldn't be immediately re-trying the operation that just failed a millisecond ago. Instead, log the failure and handle the exception:
catch (Exception ex)
{
// DO NOT call SaveChanges() here.
}
Of course, if writing to the database is failing, then logging to the database is also likely to fail. Suppose for example that the connection string is wrong or the database is down or timing out. You can't log that.
I recommend using a logging framework (log4net, NLog, etc.) as a separate dependency from your Entity Framework data access layer. It's a small learning curve, but you end up with a pretty robust logging system that can much more effectively handle problems. And can be easily configured to log to multiple places, so if writing to one error log (the database) fails then you still have another one (a file, for example).
At the very least, if persisting your data context fails, you'll need to log to a new data context. Otherwise the part that failed is still there.
Something structurally more like this:
try
{
using (var database = new DbContext())
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
}
catch (Exception ex)
{
using (var database = new DbContext())
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
}

Related

Why is the DbContext closing before I attempt this LINQ query in Entity Framework using FindAsync()?

I'm on a team using an EF, Code-first approach with ODP.Net (Oracle). We need to attempt to write updates to multiple rows in a table, and store any exceptions in a collection to be bubbled up to a handler (so writing doesn't halt because one record can't be written). However, this code throws an exception saying
System.InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.
I'm not sure why. The same behavior occurs if the method is changed to be a synchronous method and uses .Find().
InvModel _model;
public InvoiceRepository(InvModel model)
{
_model = model;
}
public void SetStatusesToSent(IEnumerable<Invoice> Invoices)
{
var exceptions = new List<Exception>();
foreach (var id in invoices)
{
try
{
var iDL = await _model.INVOICES.FindAsync(id);/*THROWS A DBCONTEXT EXCEPTION HERE*/
iDL.STATUS = Statuses.Sent; // get value from Statuses and assign
_model.SaveChanges(); //save changes to the model
}
catch (Exception ex)
{
exceptions.Add(ex);
continue; //not necessary but makes the intent more legible
}
}
}
Additional detail update: _model is injected by DI.
Remember that LINQ executes lazily - that is when you actually use the information.
The problem might be, that Your DbContext has gone out of scope...
Use .ToList() or .ToArray() to force execution at that time.

When to Throw an Exception? When to Handle an Exception (Service Layer, Controller) where?

I rewritten my question as I think it was too wordy and maybe what I am trying to achieve was lost.
I written this code in notepad so it may have mistakes and some stuff maybe not well thoughout but it is to illustrate what I see my options are.
// I wrap all code send back from service layer to controller in this class.
public class ResponseResult
{
public ResponseResult()
{
Errors = new Dictionary<string, string>();
Status = new ResponseBase();
}
public void AddError(string key, string errorMessage)
{
if (!Errors.ContainsKey(key))
{
Errors.Add(key, errorMessage);
}
}
public bool IsValid()
{
if (Errors.Count > 0)
{
return false;
}
return true;
}
public Dictionary<string, string> Errors { get; private set; }
public ResponseBase Status { get; set; }
}
public class ResponseResult<T> : ResponseResult
{
public T Response { get; set; }
}
public class ResponseBase
{
public HttpStatusCode Code { get; set; }
public string Message { get; set; }
}
Option 1 (what I am using now)
//controller
public HttpResponseMessage GetVenue(int venueId)
{
if (venueId == 0)
{
ModelState.AddModelError("badVenueId", "venue id must be greater than 0");
if (ModelState.IsValid)
{
var venue = venueService.FindVenue(venueId);
return Request.CreateResponse<ResponseResult<Venue>>(venue.Status.Code, venue);
}
// a wrapper that I made to extract the model state and try to make all my request have same layout.
var responseResult = new ResponseResultWrapper();
responseResult.Status.Code = HttpStatusCode.BadRequest;
responseResult.Status.Message = GenericErrors.InvalidRequest;
responseResult.ModelStateToResponseResult(ModelState);
return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);
}
// service layer
public ResponseResult<Venue> FindVenue(int venueId)
{
ResponseResult<Venue> responseResult = new ResponseResult<Venue>();
try
{
// I know this check was done in the controller but pretend this is some more advanced business logic validation.
if(venueId == 0)
{
// this is like Model State Error in MVC and mostly likely would with some sort of field.
responseResult.Errors.Add("badVenueId", "venue id must be greater than 0");
responseResult.Status.Code = HttpStatusCode.BadRequest;
}
var venue = context.Venues.Where(x => x.Id == venueId).FirstOrDefault();
if(venue == null)
{
var foundVenue = thirdPartyService.GetVenue(venueId);
if(foundVenue == null)
{
responseResult.Status.Code = HttpStatusCode.NotFound;
responseResult.Status.Message = "Oops could not find Venue";
return responseResult;
}
else
{
var city = cityService.FindCity(foundVenue.CityName);
if(city == null)
{
city = cityService.CreateCity(foundVenue.CityName);
if(city.Response == null)
{
responseResult.Status.Code = city.Status.Code;
responseResult.Status.Message = city.Status.Message;
return responseResult;
}
CreateVenue(VenueId, city.Response, foundVenue.Name);
responseResult.Status.Code = HttpStatusCode.Ok;
// I don't think I would return a success message here as the venue being displayed back to the user should be good enough.
responseResult.Status.Message = "";
reponseResult.Response = foundVenue;
}
}
return responseResult;
}
}
catch (SqlException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
// maybe roll back statement here depending on the method and what it is doing.
}
// should I catch this, I know it should be if you handle it but you don't want nasty messages going back to the user.
catch (InvalidOperationException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
}
// should I catch this, I know it should be if you handle it but you don't want nasty messages going back to the user.
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
}
return responseResult;
}
// another service layer.
// it is ResponseResult<City> and not city because I could have a controller method that directly calls this method.
// but I also have a case where my other method in another service needs this as well.
public ResponseResult<City> CreateCity(string CityName)
{
ResponseResult<City> responseResult = new ResponseResult<City>();
try
{
City newCity = new City { Name = "N" };
context.Cities.Add(newCity);
context.SaveChanges();
responseResult.Status.Code = HttpStatusCode.Ok;
responseResult.Status.Message = "City was succesfully added";
}
// same catch statmens like above
catch (SqlException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
// maybe roll back statement here depending on the method and what it is doing.
}
return responseResult;
}
As you can see the methods are all wrapped in the status codes as they could be directly called by the controller being public. FindCity() and CreateVenue() could also have this wrapping.
Option 2
public HttpResponseMessage GetVenue(int venueId)
{
try
{
if (venueId == 0)
{
ModelState.AddModelError("badVenueId", "venue id must be greater than 0");
if (ModelState.IsValid)
{
var venue = venueService.FindVenue(venueId);
return Request.CreateResponse<ResponseResult<Venue>>(HttpSatusCode.Ok, venue);
}
// a wrapper that I made to extract the model state and try to make all my request have same layout.
var responseResult = new ResponseResultWrapper();
responseResult.Status.Code = HttpStatusCode.BadRequest;
responseResult.Status.Message = GenericErrors.InvalidRequest;
responseResult.ModelStateToResponseResult(ModelState);
return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);
}
catchcatch (SqlException ex)
{
// can't remember how write this and too tried to look up.
return Request.CreateResponse(HttpStatusCode.InternalServerError;, "something here");
}
}
public Venue FindVenue(int venueId)
{
try
{
// how to pass back business logic error now without my wrapper?
if(venueId == 0)
{
// what here?
}
var venue = context.Venues.Where(x => x.Id == venueId).FirstOrDefault();
if(venue == null)
{
var foundVenue = thirdPartyService.GetVenue(venueId);
if(foundVenue == null)
{
// what here?
}
else
{
var city = cityService.FindCity(foundVenue.CityName);
if(city == null)
{
city = cityService.CreateCity(foundVenue.CityName);
if(city == null)
{
// what here?
}
CreateVenue(VenueId, city.Response, foundVenue.Name);
}
}
return venue;
}
}
catch (SqlException ex)
{
// should there be a try catch here now?
// I am guessing I am going to need to have this here if I need to do a rollback and can't do it in the controller
// throw exception here. Maybe this won't exist if no rollback is needed.
}
return null;
}
public City CreateCity(string CityName)
{
// if it crashes something I guess will catch it. Don't think I need to rollback here as only one statement being sent to database.
City newCity = new City { Name = "N" };
context.Cities.Add(newCity);
context.SaveChanges();
return newCity;
}
As you see with option 2, I might still need to wrap it in try catches for rollbacks and I am not sure how to handle advanced business validation.
Also with catching everything in the controller and sending back vanilla objects(without my wrapper) I am unsure how to do fine grain HttpStatus codes(say like notFound,Create and such)
Sorry for the brief response, but here is my general rule - if an exception occurs which you expect might happen, deal with it - either by retrying or telling the user something went wrong and giving them options to fix it.
If an unexpected exception occurs, if it's something you can deal with (e.g a timeout which you can retry) try to deal with it, otherwise get out - just think what any MS app does - e.g. office - you get an apology that something went wrong and the app ends. It's better to end gracefully than to potentially corrupt data and leave things in a real mess.
This is an article with Java-specific concepts and examples, but the broad principles here are the way to go.
Distinguish between fault exceptions, which are catastrophic and unrecoverable, and contingency exceptions, which are very much recoverable. Let the faults "bubble" to the fault barrier, where you handle appropriately. For example, you might log the error, E-mail someone or send a message to a message queue, and present the user with a nice, informative error page.
Whatever you do, be sure to preserve all the exception information from the source.
Hope that helps.
Throw an exception wherever your code determines that something has gone wrong.
You always need to handle exceptions in methods which are called directly by the end-user. This is to cater for unexpected errors which your code doesn't have specific handling for. Your generic handling code would typically log the error and may or may not include letting the user know that an unexpected error has occurred.
But if there are errors which you can expect ahead of time, you'll often want to handle these lower down in the code, nearer to the point at which they occur, so that your application can "recover" from the error and continue.
I think exceptions are useful any time you need to return details of a failure from a method, whilst being able to use the ideal return type for the method you're calling.
You said in your question:
Now for me I try to return error messages back to the the controller
and try not to really catch anything in the controller.
If the service method is supposed to ideally return a Venue object, how do you return this potential error message back to the controller? an out parameter? change the return type to something which has an error message property on it?
If you're doing either of those options, I think you're reinventing the wheel... i.e. creating a way to return exception information when one already exists.
Finally, Exceptions are strongly typed representations of what went wrong. If you return an error message, then that is fine to send back to the user, but if you need to programatically do different things based on the details of the error, then you don't want to be switching on magic string.
For example, wouldn't it be handy to differentiate between authorization errors and not found errors so you can return the most appropriate http status code to the user?
Don't forget that the Exception class has a Message property you can simply return to the user if you want to use it that way
To make sure I understand the question, your are creating a web service and want to know when to handle and when to throw exceptions.
In this situation I would strongly recommend that you catch all exceptions. "Unhandled" exceptions are very bad form. On web sites they result in displays that range from meaningless to dangerous by exposing internal information that you do no want the public to see.
If this is a good sized program I suggest that you create your own MyException class which derives from System.Exception. The purpose of this is provide a place for you to add additional information specific to your application. Here are some typical things I like to add to my MyException classes:
An ID number that will help me find the location in the code where the problem occurred.
A "LogMessage" method that logs the exception, sometimes to the Windows Event Log. Whether or not you log and to which log you write depends on what you want recorded, and the severity of the situation.
An indicator that shows the exception has been logged so the above method will not log twice even if it gets called more than once.
Anything else that might be useful given the circumstance.
I also like to put the text of the messages in an external resource file, like an XML document, and key them to the error number that you assign. This allows you to change the error text to improve clarity without having to redeploy the application.
Catch all exceptions and create a new instance of your MyException type and put the original exception into inner exception property. Below the first level of my application, I always throw one of my MyException instances rather than the original exception.
At the top level (application level), NEVER let an exception go unhandled and never throw your own exception. A better way is to return an error code and message in your data contract. That way the client application will only get what you want them to see. The only exceptions they'll need to worry about are the ones outside your scope, i.e. configuration errors or communication failures. In other words if they are able to invoke your service and the network stays connected you should give them a response they can interpret.
Hope this helps.
PS I didn't include a sample exception as I am sure a little searching will find many. Post if you want me to put up a simple sample.
Use try catch at all levels and bubble it up. Optionally, log the error in a file or database. I use text file - tab delimited. Capture at each level
1. Module Name (Use C# supplied methods to get this)
2. Method Name
3. Code Being Executed (User created - "Connecting to database")
4. Error Number
5. Error Description
6. Code Being Executed (User created - "Accessing database")
7. Error Number for the end user
8. Error Description for the end user
Additionally, I also pass a unique identifier like - Session Id in case of Web, Logged in User Id, User Name (if available)
I always have the Exception catch block. In here I set the error number as -0 and the message from the exception object as the error description. If it is SQL Server related - I capture SQL Exception. This generates an error number - I use that.
I want to extend this some more though.

Transactions commit and rollback with Entity Framework, Mysql and LINQ to SQL in C#

My problem is that the transaction is not working properly it should not save the data for one table if an exception occurs during the trascation
When all the table is correct then only save data.
Consider the following:
databaseEntites objEntites = null;
using (objEntites = new databaseEntites())
{
objEntites.Connection.Open();
using (System.Data.Common.DbTransaction transaction =
objEntites.Connection.BeginTransaction())
{
try
{
customer objcust=new customer();
objcust.id=id;
objcust.name="test1";
objcust.email="test#gmail.com";
objEntites.customer.AddObject(objcust);
order objorder=new order();
objorder.custid=objcust.id;
objorder.amount=500;
objEntites.order.AddObject(objorder);
objEntites.SaveChanges();
transaction.Commit();
}
catch()
{
transaction.Rollback();
}
}
}
In this my second table column name is not correct and on SaveChanges() giving the exception.
When i see the database and found that it saving the data for customer table which is wrong i want data will go in the customer table when all table is correct and this savechanges either save for all table or not save for any.
For this i have also try the TransactionScope
using (TransactionScope tscope =
new TransactionScope(TransactionScopeOption.RequiresNew))
{
......all the code here....
objEntites.SaveChanges(false);
tscope.Complete();
objEntites.AcceptAllChanges();
}
But its giving the same issue as described above.
Thanks in advance.
You can use database transaction or EF TransactionScope. For using database transaction it is enough to do as below:
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
//Some stuff
dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
And for using second way that EF TransactionScope just use easily as below:
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
try
{
//Some stuff
scope.Complete();
}
catch (Exception)
{
//Don't need call any rollback like method
}
}
The point is no Rollback() method exist in the TransactionScope (against the normal ADO.NET Transaction) and Unless you call the Complete() method, the transaction do not complete and all the changes are rolled back automatically. You can see MSDN for better understand: http://msdn.microsoft.com/en-us/data/dn456843.aspx
Hope this help
If you have already a try ... catch block, you don't need using - just add finally. The following example should have everything you need:
databaseEntites objEntites = null;
var System.Data.Common.DbTransaction transaction = null;
try
{
objEntites = new databaseEntites();
objEntites.Connection.Open();
transaction = objEntites.Connection.BeginTransaction();
customer objcust=new customer();
objcust.id=id;
objcust.name="test1";
objcust.email="test#gmail.com";
objEntites.customer.AddObject(objcust);
order objorder=new order();
objorder.custid=objcust.id;
objorder.amount=500;
objEntites.order.AddObject(objorder);
objEntites.SaveChanges();
transaction.Commit();
}
catch()
{
if (transaction != null) transaction.Rollback();
}
finally
{
if (objEntites != null && objEntites.Connection.State != System.Data.ConnectionState.Closed
&& objEntites.Connection.State != System.Data.ConnectionState.Broken)
objEntites.Connection.Close();
}
Hints:
The finally block is executed even after an exception has occured, hence in case of an exception the exception handling code is executed first, then the code in the finally block. Only if severe exceptions (system errors) - such as a StackOverflowException - occur, it is not executed but you can't handle such kinds of exceptions anyway easily. For more information about this topic please look here.
For SaveChanges you can also use the option System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave, which I prefer because it guarantees that every entity object has its changes accepted after successful save.
BeginTransaction allows also to specify the kind of transaction, but I would not use the parameter options because if you omit it then it creates a transaction as specified by the database's default - so the administrator is still able to change this easily if required. But if you need to specify it, ensure that you don't hardcode it, but allow to configure it in the App.Config or Web.Config file.
Please let me know if that works for you.

How to rethrow exceptions in a program with multiple layers?

I have an MVC EF5 setup, with classes:
Program - this is the controller
UserInterface - this is the view, responsible for displaying and prompting for data.
DataAccess - Model, this Creates, Reads, Updates, and Deletes data in my EF model classes
When the DataAccess class tries to do a CRUD operation on my database, if it catches an error, it needs to be handled, my UserInterface class needs to print messages to the user, reporting any errors if neccessary. So, when an error happens, it needs to go through the program class first, then to the UserInterface class, because data layer shouldn't directly communicate to the presentation layer.
It was suggested to me that I don't pass or return the exception to a calling function, but that I should "throw a new simpler exception to the layers above". All this talk about exceptions is confusing to me because My experience with exceptions is limited to this format:
try
{
// stuff
}
catch (exception ex)
{
console.writeline(ex.ToString());
}
I've done some of my own research to try and find the answer to this problem, and I've learned a few things but don't know how to put it all together:
I learned:
throw; rethrows an exception and preserves the stack trace
throw ex throws an existing exception, such as one caught in a catch block. and resets the stack trace.
There is a property called Exception.StackTrace. I understand that each time an exception is thrown, the frames in the call stack are recorded to the Exception.StackTrace property.
However, I don't know where to place my try/catch blocks to utilize rethrowing
Is it something like the following code? Or am I missing the point on how this works?
EDITED: (added a little more to make sense of this guesswork to others)
void MethodA()
{
try
{
MethodB();
}
catch (MyExceptionType ex)
{
// Do stuff appropriate for MyExceptionType
throw;
}
}
void MethodB()
{
try
{
MethodC();
}
catch (AnotherExceptionType ex)
{
// Do stuff appropriate for AnotherExceptionType
throw;
}
}
void MethodC()
{
try
{
// Do Stuff
}
catch (YetAnotherExceptionType ex)
{
// Do stuff appropriate for YetAnotherExceptionType
throw;
}
}
There is more than how you use different type of exception handling. Functionally you should define what layers has to do what with a exception.
Like data layer => dont throw anything other than DataException or SQLException. Log them and throw back a generic database exception back to UI.
Business layer => log and rethrow simple bussiness exception
UI layer => catch only business exception and alert it in a message inside business exception
Once all this is defined, you can use what you have learned and summarized in question to build this.
What (I think) was suggested you do by throw a new simpler exception is that you translate the exceptions from the lower layers into new, higher level exceptions for consuming in the outer layers. The lower level exceptions are not suitable for consumption at the upper levels of the program.
For example, in LINQ to Entities, the method Single() will throw an InvalidOperationException when the sequence has no elements. However, this exception type is very common, so catching it in the user interface levels is hard to do: how would you differentiate between different possibilities of this exception being thrown (for example, modifying a read-only collection)? The solution is to translate the exception into another (new, user-defined) type that the application can easily handle.
Here is a simple example of the idea:
public class MyUserService {
public User GetById(int id) {
try {
using(var ctx = new ModelContainer()) {
return ctx.Where(u => u.Id == id).Single();
}
}
catch(InvalidOperationException) {
// OOPs, there is no user with the given id!
throw new UserNotFoundException(id);
}
}
}
Then the Program layer can catch the UserNotFoundException and know instantly what happened, and thus find the best way to explain the error to the user.
The details will depend on the exact structure of your program, but something like this would work in an ASP.NET MVC app:
public class MyUserController : Controller {
private MyUserService Service = new MyUserService();
public ActionResult Details(int id) {
User user;
try {
user = Service.GetById(id);
}
catch(UserNotFoundException) {
// Oops, there is no such user. Return a 404 error
// Note that we do not care about the InvalidOperationException
// that was thrown inside GetById
return HttpNotFound("The user does not exist!");
}
// If we reach here we have a valid user
return View(user);
}
}

Annoying SQL exception, probably due to some code done wrong

I started working on this "already started" project, and I'm having a really annoying error when trying to execute some interactions with SQL Server 2008:
The server failed to resume the
transaction. Desc.:
One of these errors I get in this specific method call:
The aspx.cs Call:
busProcesso openProcess = new busProcesso(pProcessoId);
try
{
if (openProcess.GetDocument() == null)
{
//Irrelevant code.
}
}
catch{ //... }
The Business class (relevant part):
public class busProcesso : IbusProcesso
{
public Processo vProcesso { get; set; }
RENDBDataContext db;
public busProcesso()
{
vProcesso = new Processo();
}
public busProcesso(decimal pProcessoId)
{
db = new RENDBDataContext();
try
{
vProcesso = db.Processos.SingleOrDefault(x => x.Id == pProcessoId);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public string GetDocument()
{
try
{
string document = null;
foreach (Processo_has_Servico ps in ListaServicosProcesso())
{
if (ps.Servico.Document != null) //Get the error right at this line.
{
document = ps.Servico.Document;
}
}
return document ;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public IQueryable<Processo_has_Servico> ListaServicosProcesso()
{
db = new RENDBDataContext();
try
{
return from ps in db.Processo_has_Servicos
join s in db.Servicos on ps.Servico_Id equals s.Id
where ps.Processo_Id == vProcesso.Id
select ps;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
}
As I said, the error occurs right at the line:
if (ps.Servico.Document != null) from the GetDocument() method.
Opening SQL Server Activity Monitor, I see there is a process for my database (.Net SqlClient Data Provider)
After some time/use (when I start to get the "server failed to resume the transaction" error), I go to the SQL Server Activity Monitor and there's around 5 or 6 more identical processes that weren't killed and (probably) should've been. When I manually kill them, the error stops for a while, until it starts again.
I'm not really good at working in OO and all, so I'm probably missing something, maybe some way to close one of these connections. Also, any help/tip about this structure will be welcome.
PS. The error doesn't happen everytime. Sometimes it runs just perfectly. Then it starts to give the error. Then it stops. Sometimes it happens just once.. pretty weird.
The code in ListaServicosProcesso is creating the context db. Then it is returning an IQueryable.
At this point no request has been sent to the database.
Then there is a for each in the code. At this point EF says "I need to get the data from the database". So it tries to get the data.
But the context db is now out of scope, so it crashes, on the first line that tries to use the data.
There are 2 ways to get around this:
return a list from ListaServicosProcesso, this will force the database call to execute
move the for each into ListaServicosProcesso
Edit
Pharabus is correct db is not out of scope. The problem is here:
db = new RENDBDataContext();
A new instance of the context is being created without the old one being disposed. Try Dispose of db at the end of ListaServicosProcesso. Even better place db in a using statement. But then the foreach must be moved inside the using statement.
Here's a couple of ideas to try.
1/ You can attach SQL server profiler to see the query that is being executed, which will allow you to copy and paste that query to see the data that is in the database. This might be help.
2/ You never check whether ps.Servico is null - you jump straight to ps.Servico.Document. If ps.Servico is null then you will get a null reference exception if you try to access any properties on that object.
I'm not sure of the exact cause of the error you're seeing (if you Google it, the references are all over the place...), but there are a few things you could improve in your code and I've found that just cleaning things up a bit often makes problems go away. Not always, but often.
I agree with the other answerers that it would help to keep better track of your DataContext(s). For example in you're creating it once in the constructor, then again in ListaServicosProcesso(). At that point vProcesso is on one DataContext and other entities will be on another, which gets messy.
I think you could simplify the whole thing a bit, for example you could combine GetDocument() and ListaServicosProcesso() like this:
public string GetDocument()
{
try
{
// Are you sure vProcesso is not null?
if (vProcesso == null)
return null;
// Only create the context if it wasn't already created,
if (db == null)
db = new RENDBDataContext();
return db.Processo_has_Servicos
.Where(ps => ps.Processo_Id == vProcesso.Id && ps.Servico.Document != null)
.Select(ps => ps.Servico.Document) // use an implicit join
.SingleOrDefault();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}

Categories

Resources