Convert System.Data.Entity.DynamicProxies to (non proxy) class in C# - c#

I am getting some data from the database and storing this in a global variable as shown:
//Global Variable
public static List<stuff> Stuff;
using (var context = new StuffContext())
{
stuff = new List<stuff>();
stuff = (from r in context.Stuff
select r).ToList();
}
The problem I am having is that the context closes and when I wish to access some of the data stored in the global variable, I cannot.
The data is of System.Data.Entity.DynamicProxies.Stuff instead of Application.Model.Stuff which means I then receive this error when I try to do something with the data:
"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
My question is how can I, using the above code as an example, convert / cast to the type that I want so that I can use the data else where in my application?
Edit: Quick screen grab of the error:

The Solution was due to lazy loading after all.
I had to tell the query to grab everything so that when the context closes I still had access to the data.
This is the change I had to make:
public static List<stuff> Stuff;
using (var context = new StuffContext())
{
stuff = new List<stuff>();
stuff = (from r in context.Stuff
.Include(s => s.MoreStuff).Include(s => s.EvenMoreStuff)
select r).ToList();
}

Try to Disable ProxyCreationEnabled In Your Project BbContext constructor As Follow:
Configuration.ProxyCreationEnabled = false;

Related

Prevent object dispose inside using block

Workflow:
I have a winform app with two forms, in the 1st form I query a liteDB and it manipulates an IEnumerable<T> instance inside a using block with retrieved data.
IEnumerable<student> searchResult;
using(var db = new LiteDatabase(#"C:\Temp\MyData.db"))
{
var col = db.GetCollection<student>("students");
col.EnsureIndex(x => x.contact.phone);
searchResult = col.Find(x => x.contact.phone == "123456789");
}
Form2 frm2 = new Form2();
Form2.profileData = searchResult.AtElement(index);
Problem:
I then, need to send an element of searchResult<student> to 2nd form in order to show user, as you can see in the last 2 lines of above code.
But since it's inside using block, I get System.ObjectDisposedException.
Data types and exception:
studentCollection.Find():
searchResult:
Exception:
Addition:
What I already though of as possible way is:
Override and nullify existing dispose() method then call my own implemented method after I'm done; Which is basically equals to not having a using block, except that I don't have to take care of disposing other objects in above using block, but only searchResult<student>.
P.S:
I'm newbie at whole thing, appreciate the help and explanation
I'm not familliar with LiteDb, but I would assume it returns a proxy object for the database. So when the database is disposed, the proxy-object is no longer usable.
The simple method to avoid the problem is to add .ToList() after the .Find(...). This will convert the proxy-list to an actual List<T> in memory, and it can be used after the database is disposed. It is possible that the student objects inside the list are also proxies, and if that is the case this will fail.
If that is the case you either need to find some way to make the database return real, non-proxy objects, or extend the lifetime of the database to be longer than that of your form, for example
IList<student> myIList;
using(var db = new LiteDatabase(#"C:\Temp\MyData.db"))
{
var col = db.GetCollection<student>("students");
col.EnsureIndex(x => x.contact.phone);
myIList = col.Find(x => x.contact.phone == "123456789");
using(var frm2 = new Form2()){
frm2.profileData = myIList.AtElement(index);
frm2.ShowDialog(this);
}
}
Note the usage of .ShowDialog, this will block until the second form has been closed. That is not strictly necessary, but it makes it much easier to manage the lifetime of the database.
You need to access the element before exiting the using block.
using(var db = new LiteDatabase(#"C:\Temp\MyData.db"))
{
var col = db.GetCollection<student>("students");
col.EnsureIndex(x => x.contact.phone);
var searchResult = col.Find(x => x.contact.phone == "123456789");
Form2 frm2 = new Form2();
Form2.profileData = searchResult.AtElement(index);
}

DataReader Error with Lazy Singleton Pattern in C# when Manager Called More Than Once

I'm using the lazy singleton pattern in C# for my data managers. The code in my manager looks like this:
private static readonly Lazy<ConditionManager> singleton =
new Lazy<ConditionManager>(() => new ConditionManager());
public static ConditionManager Instance { get { return singleton.Value; } }
Then in my code, I am trying to see if the item exists before I create it:
//see if condition exists. If it doesn't then create it.
List<Condition> conditions = ConditionManager.Instance.Select
(question.Id, ConditionType.ProjectQuestion);
Condition c;
if (conditions.Count == 0)
{
c = new Condition(question.Id, ConditionType.ProjectQuestion, ReleaseId);
c.Id = ConditionManager.Instance.Insert(c);
}
The problem is that, when I call the Insert, I get the dreaded error: "There is already an open DataReader associated with this Command which must be closed first." I have found a workaround (I have one call to the ConditionManager that both checks to see if it exists and then returns either the existing one of the newly created one), but what is the proper way to handle this? How do I close the first instance?

recover "DbContext" lost out after a method

I need your help.
I begin to ASP.net and I fail to retrieve a "dbcontext" to display my request in a "datagrid". Here is my code:
public IQueryable<DiagTab> Clooper(string m_ValEnvoi)
{
string Ladatatable = m_ValEnvoi;
using (var db = new DiagEntities())
{
var secki = db.DiagTabs.Where(Ladatatable); // Ladatatabase = Dynamic LinQ
return secki;
}
I call this way (no error)
TheLoop pilou = new TheLoop();
pilou.Clooper(Valtest);
var olami = pilou.Clooper(Valtest);
but if i try this:
var selection_click = olami;
GridView1.DataSource = selection_click.ToList();
GridView1.DataBind();
the code is interrupted and displays "Could not complete the operation because the DbContext has been deleted".
Is it possible to get the paste has Dbcontext for this request?
thanks for your help
You should call ToList() inside the method, before disposing the DbContext.
Don't use using which dispose the DiagEntities and instead of it, if you want to use it in several methods just declare a property for your DiagEntities in the class constructor.
public IQueryable<DiagTab> Clooper(string m_ValEnvoi)
{
string Ladatatable = m_ValEnvoi;
var secki = db.DiagTabs.Where(Ladatatable); // Ladatatabase = Dynamic LinQ
return secki;
}

Cannot foreach through data context

i want to compare through 2 information, one is user input and second is admin ID in database. in my project, i'm using WCF Ria. i did created one auto-generated Domain Service Class and the code to retrieve everything in tblAdmin was auto-generated. i load the data in this way ::
var context = new OrganizationContext();
var x = context.tblAdmins;
context.Load(context.GetTblAdminsQuery());
cb1.ItemsSource = x;
it can load in this way, but i cannot get the x.adminID with this. so i tried this ::
foreach (var admin in x)
{
cb1.Items.Add(admin.adminID);
}
but failed... may i know is that possible to dig through the data without foreach or is there something wrong in my code ??
Looks like the problem is that the context.Load call is asynchronous - to get the result you need to pass a callback and get your data there:
context.Load(context.GetTblAdminsQuery(), LoadCompleted, null);
and:
public void LoadCompleted(LoadOperation<YOUR_ENTITY_TYPE> op)
{
foreach(var item in op.Entities)
{
//item is your entity, you can get item.adminID
}
}

How to access entity's properties outside context using Entity Framework?

I'm new to Entity Framework (working mostly with NHibernate with ActiveRecord before) and I'm stuck with something, that I think should be easy...
I have a User Entity, and created partial User class so I can add some methods (like with NHibernate). I added GetByID to make getting user easier:
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Where(qq => qq.UserID == userID).Single();
}
}
Now in the same class I want to log moment of logging in, and I try to do:
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
The problem is I can't access user.LoginLogs because user's context is already disposed... Most likely I'm missing something obvious here, but creating always full queries like:
context.Users.Where(qq => qq.UserID == userID).Single().LoginLogs.Add(log);
doesn't seem like a good option...
I've read about Repository pattern but I think it's too big gun for such task. Please explain me what am I doing wrong. Thanks in advance!
EDIT
To picture what I'd like to do:
//somewhere in business logic
var user = User.GetByID(userID);
var posts = user.GetAllPostsForThisMonth();
foreach(var post in posts)
{
Console.WriteLine(post.Answers.Count);
}
Normally I'm not allowed to do this because I can't get post.Answers without context...
You are closing the object context and then trying to add a log to the user that is detached. You need to attach the user so the objectContext know what has been changed or added.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = context.User.Where(p=>p.UserID == userID); //<= The Context now knows about the User, and can track changes.
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
Update
You can also attach the object.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.User.Attach(user);
context.SaveChanges();
}
}
Update
var getFirstLogin = from p in User.GetUserById(userId)
select p.LoginLogs.FirstOrDefault();
NB if LoginLogs is a different table you will need to use Include.
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Include("LoginLogs").Where(qq => qq.UserID == userID).FirstOrDefault();
}
}
If you are open to using stored procedures (and they work nicely with EF), you can return the user object and simultaneously add to the log table with a single call to the database.
I used to do everything with SP's in my pre-EF/ORM days, when I went to EF I tried very hard to avoid using stored procedures to avoid falling back into my old habits, but now I have found that the selective use of stored procedures you can have the benefits of both -the EF way of doing things, and the super functionality/performance that a well written SP can provide.

Categories

Resources