Am coding on visual studio 2012 and using Entity Model as my Data layer. However, my drop down control with the Linq statement tend to throw an unhandled exception when the page tries to load (stated title above). Here is my code below;
using (AdventureWorksEntities dw = new AdventureWorksEntities())
{
ddlCon.DataSource = (from em in dw.Employees
select new { em.Title, em.EmployeeID });
ddlCon.DataTextField = "Title";
ddlCon.DataValueField = "EmployeeID";
ddlCon.DataBind();
ddlCon.Items.Insert(0, new ListItem("--Select--", "--Select--"));
}
I want to know why that error occurred
What should be the proper way to bind to a control when using LINQ?
The error is fairly clear - you can't bind directly to the query results, but need to populate some local collection instead.
The simplest way to do this is to convert it to a List<T>, via ToList():
ddlCon.DataSource = (from em in dw.Employees
select new { em.Title, em.EmployeeID }).ToList();
Or if you want to avoid writing a LINQ expression you could just do this:
var dbContext = new EF.CustomerEntities();
gvCustomers.DataSource = dbContext.CustomersTable.ToList();
though this question has already been answered still I want to show that you can even get the answer directly from the message box as well (i got the same error)
ERROR DIALOGUE BOX IMAGE
using (var retrive=new Models.Academy_MSDBEntities())
{
var query = retrive.Students.Where(s => s.Year == year).ToList();
return query;
}
Related
In the earlier versions of Entity Framework, we were able to reach the Context out of ObjectQuery in order to read Parameters, Connection, etc. as below:
var query = (ObjectQuery<T>)source;
cmd.Connection = (SqlConnection)((EntityConnection)query.Context.Connection).StoreConnection;
cmd.Parameters.AddRange(
query.Parameters.Select(x => new SqlParameter(
x.Name, x.Value ?? DBNull.Value)
).ToArray()
);
When I look at the DbSet<T> object, I am unable to find any equivalent of this. My purpose here is to create extensions which will manipulate the query and get the result out of it.
Here is an instance: http://philsversion.com/2011/09/07/async-entity-framework-queries
Or should I write the extension for DbContext class and work with Set method?
Any idea?
Edit
Here is what I did so far. Basic implementation so far but certainly not ready for production. Any suggestions on this?
public static async Task<IEnumerable<T>> QueryAsync<T>(this DbContext #this, System.Linq.Expressions.Expression<Func<T, bool>> predicate = null)
where T : class {
var query = (predicate != null) ? #this.Set<T>().Where(predicate) : #this.Set<T>();
var cmd = new SqlCommand();
cmd.Connection = (SqlConnection)(#this.Database.Connection);
cmd.CommandText = query.ToString();
if (cmd.Connection.State == System.Data.ConnectionState.Closed) {
cmd.Connection.ConnectionString = new SqlConnectionStringBuilder(cmd.Connection.ConnectionString) {
AsynchronousProcessing = true
}.ToString();
cmd.Connection.Open();
}
cmd.Disposed += (o, e) => {
cmd.Clone();
};
var source = ((IObjectContextAdapter)#this).ObjectContext.Translate<T>(
await cmd.ExecuteReaderAsync()
);
return source;
}
This is a nice workaround, although I don't think you can make it much more generally applicable than what you already have.
A few things to keep in mind:
- Depending on the EF query, e.g. if you are using Include or not, the columns returned in the reader might not match the properties in the type T you are passsing.
- Depending on whether you have inheritance in your model, the T that you pass to translate may not always be the right thing to materialize for every row returned.
- After the task returned by ExecuteReaderAsync completes, you still have to retrieve each row, which depending on the execution plan for the query and the latency you are getting with the server is potentially also a blocking operation.
Async support is not coming to EF in 5.0 but we worked with other teams to make sure we have all the necessary building blocks included in .NET 4.5 and the feature is pretty high in our priority list. I encourage you to vote for it in our UserVoice site.
i have a webservice that uses linq to sql to populate a list of objects from the result:
linqDBContext db = new linqDBContext();
public List<lut_flavorName> GetFlavors()
{
List<lut_flavorName> results =
(from a in db.lut_flavorNames
select a).ToList();
return results;
}
in the completed event, im trying to receive that into an observable collection (or even a typical list for that matter)
client.GetFlavorsCompleted += delegate(object s, GetFlavorsCompletedEventArgs es)
{
ObservableCollection<Object> list = es.Result;
//more code
};
The error that I'm getting is that I can't implicity convert from ArrayOfXElement to ObservableCollection
I tried casting but it still says it cannot convert. I'm assuming that instead of getting an object type "lut_flavorNames" i'm getting ArrayOfXElement because the silverlight project has no reference to the data context. How do I solve this? Is the problem caused by the fact that I'm using linq-to-sql instead of linq-to-entities or is there a way to make this work?
You service returns a List<lut_flavorName> which the service proxy treats as a lut_flavorName[], not an ObservableCollection, so of course it will not cast.
Why not create a new ObservableCollection and add the list via this constructor?
e.g.
client.GetFlavorsCompleted += delegate(object s, GetFlavorsCompletedEventArgs es)
{
ObservableCollection<Object> list = new ObservableCollection<Object>(es.Result);
//more code
};
Note: most services really only need to return an IQuerable (lets you do server-side paging) or an IEnumerable.
I am very new to linq and am trying to figure out how to accomplish the following:
Currently, I have a Winforms project that has a Base Form with a DataRow as one of it's members. I have several derived Forms populate the DataRow based on data from a DataTable (SQL Query Result). There are controls on the derived Forms that are populated with the values from the data as well. When the Save button on the derived Forms is clicked, the DataRow in the Base Form is updated and then the Derived Form updates the Database via a DataAdapter.
I wanted to replace all of the SQL Commands using linqs so I tried implementing this functionality using LINQ by the following:
I created my Linq query in the Derived Form and assigned the result to an Object in the Base Form. I cast the Object in the Base Form to the class type of the Linq query and use reflection to populate all the controls on the Derived Form. When the save button is clicked I update the Object but I am not able to update the Database.
The problem that I can't solve is how to update the database once the object is updated. At this point I don't have the Data Context that I used for the linq query.
I am using an SQL function within the linq query so I had to create a separate class for these values as I was getting an anonymous type error. I am probably missing something here.
Any help would be most appreciated as I really how clean the linq code is.
Edit (Copied from Brad's Edit to Tomas's answer):
Here are the 3 steps of my code.
Step 1 - Get a singe record of data from database
private void GetDatabaseDetailData()
{
_db = new PriorityDataContext();
DetailData = (from db in _db.tblDatabases
where db.DatabaseID == Id
select db).SingleOrDefault();
DeveloperData = (from db in _db.tblDatabases
where db.DatabaseID == Id
select new DeveloperInfo
{
DeveloperName = _db.func_get_employee_name(db.Developer)
}).SingleOrDefault();
}
Step 2 - Populate all controls whos name exists in the Object. The DetailData Object is cast to the specific type passed into this method. All code not shown for brevity.
protected virtual void PopulateDetailControlsA(List<Control> controlContainers, string srcDataTableName)
{
Object data = null;
Type type = null;
switch (srcDataTableName)
{
case "tblDatabases" :
type = typeof(tblDatabase);
data = (tblDatabase)DetailData;
break;
}
if (type != null)
{
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var controlContainer in controlContainers)
{
foreach (var propertyInfo in properties)
{
if (!ControlExists(controlContainer, propertyInfo.Name)) continue;
var txtControl = controlContainer.Controls[propertyInfo.Name] as ExtendedTextBox;
if (txtControl != null)
{
try
{
var value = propertyInfo.GetValue(data, null).ToString();
if (propertyInfo.Name == "row_oper_name" || propertyInfo.Name == "row_last_chng_oper_name")
{
txtControl.Text = RowOperatorData.RowOperatorName;
txtControl.ValueMember = propertyInfo.GetValue(data, null).ToString();
}
else
txtControl.Text = value;
}
catch (NullReferenceException)
{
}
continue;...........
Step 3 - Try and save changes back to database in the derived From.
private void SaveData()
{
try
{
_db.SubmitChanges();
}
catch (Exception sqlException)
{
}
}
What I am really unclear about hear is how to store the result set in the Base Form so that I can use the same code for many different queries. The DataRow worked great because I use the some code for over 25 derive Forms.
If I understand you correctly, you create the DataContext in a derived form and then use it to write some queries (in a derived form). In order to be able to update the database, your queries must return the entities obtained from the table (i.e. the select clause should just return the entity). For example:
DataContext db = // ...
var q = from p in db.Things
where p.Some > 10 select p;
If you then modify the entities, you can use db.SubmitChanges() to store the changes (made to the entity objects) to the database. For this, you need the original db value.
In your scenario, you'll need to store the DataContext (as a field) in the derived form. If you need to perform the update from the base form, then I suggest you define a virtual method:
// Base form
protected abstract void UpdateDatabase();
// Derived from with field 'db' storing 'DataContext'
protected override void UpdateDatabase() {
db.SumbitChanges();
}
I have a problem with Linq and ObservableCollections in my WPF application.
Context of the problem:
I've created a very simple SQL database with two tables: User and BankAccounts.
The User Table has an one-to-many relationship with the BankAccounts Table. Next I've created Linq-to-SQL dataclasses, which worked fine ==> the assosiation between the two tables was detected as well.
Next I've created a function to retreive all Users which works fine:
DataClassesDataContext dc = new DataClassesDataContext
var query = from u in dc.Users
select u;
Now suppose I want to add a new BankAccount to each user (not very likely but still).
I could add the following code
for each(User u in query)
{
u.BankAccounts.Add(New BankAccount());
}
The above works all fine. The BankAccounts property is automaticly part of the User class, due to the assosiation in the database and Linq DataClasses.
However, in my application I first add the query results to an ObservableCollection. Hereby I could use all sorts off databinding and changenotification. This is accomplished by the following code;
ObservableCollection<User> oUsers = new ObservableCollection<User>(query);
Problem: Within the ObservableCollection I can't do anyting with the users BankAccounts property because it is now of type EntitySet<>. So I can't do the following statement anymore.
for each(User u in oUsers)
{
u.BankAccounts.Add(New BankAccount());
}
Somehow, when queryresults are added to an observablecollection It is not possible to acces the user.BankAccounts properties anymore. However, it is possible to bind the BankAccounts Property to any control, like a listbox, and it contains the correct data.
Does someone now how I can create an observableCollction (or similar collection) from wich I can access these "assosiated" properties? I'm realy looking forward for to a solution.
Thanks in advance!
Best regards,
Bas Zweeris
E: Bas.Zweeris#Capgemini.com
Keep track of the original query which will implement IQueryable, you can run any further queries you need against that.
The ObservableCollection should just be for WPF to have something to bind to - its very useful if you want to add a new collection item but not have it pushed to the database before the user has had chance to edit it.
eg.
// Create a new blank client type
var ct = new ClientType()
{
IsArchived = false,
Description = "<new client type>",
Code = "CT000",
CanLoginOnline = true
};
// Tell the data source to keep track of this object
db.ClientTypes.InsertOnSubmit(ct);
// Also add the object to the observable collection so that it can immediately be shown in the UI and editted without hitting the db
clienttypes.Add(ct);
I have a grid bound to a BindingSource which is bound to DataContext table, like this:
myBindingSource.DataSource = myDataContext.MyTable;
myGrid.DataSource = myBindingSource;
I couldn't refresh BindingSource after insert. This didn't work:
myDataContext.Refresh(RefreshMode.OverwriteCurrentValues, myBindingSource);
myBindingSource.ResetBinding(false);
Neither this:
myDataContext.Refresh(RefreshMode.OverwriteCurrentValues, myDataContext.MyTable);
myBindingSource.ResetBinding(false);
What should I do?
I have solved the problem but not in a way I wanted.
Turns out that DataContext and Linq To SQL is best for unit-of-work operations. Means you create a DataContext, get your job done, discard it. If you need another operation, create another one.
For this problem only thing I had to do was recreate my DataContext like this.dx = new MyDataContext();. If you don't do this you always get stale/cached data. From what I've read from various blog/forum posts that DataContext is lightweight and doing this A-OK. This was the only way I've found after searching for a day.
And finally one more working solution.
This solution works fine and do not require recreating DataContext.
You need to reset internal Table cache.
for this you need change private property cachedList of Table using reflection.
You can use following utility code:
public static class LinqDataTableExtension
{
public static void ResetTableCache(this ITable table)
{
table.InternalSetNonPublicFieldValue("cachedList", null);
}
public static void ResetTableCache(this IListSource source)
{
source.InternalSetNonPublicFieldValue("cachedList", null);
}
public static void InternalSetNonPublicFieldValue(this object entity, string propertyName, object value)
{
if (entity == null)
throw new ArgumentNullException("entity");
if(string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException("propertyName");
var type = entity.GetType();
var prop = type.GetField(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
if (prop != null)
prop.SetValue(entity, value);
// add any exception code here if property was not found :)
}
}
using something like:
var dSource = Db.GetTable(...)
dSource.ResetTableCache();
You need to reset your BindingSource using something like:
_BindingSource.DataSource = new List();
_BindingSource.DataSource = dSource;
// hack - refresh binding list
Enjoy :)
Grid Data Source Referesh by new query instead just Contest.Table.
Simple Solution < But Working.
Whre is eg.
!!!!! Thanks - Problem Solved after no of days !!! but with so simple way ..
CrmDemoContext.CrmDemoDataContext Context = new CrmDemoContext.CrmDemoDataContext();
var query = from it in Context.Companies select it;
// initial connection
dataGridView1.DataSource = query;
after changes or add in data
Context.SubmitChanges();
//call here again
dataGridView1.DataSource = query;
I have the same problem. I was using a form to create rows in my table without saving the context each time. Luckily I had multiple forms doing this and one updated the grid properly and one didn't.
The only difference?
I bound one to the entity similarly (not using the bindingSource) to what you did:
myGrid.DataSource = myDataContext.MyTable;
The second I bound:
myGrid.DataSource = myDataContext.MyTable.ToList();
The second way worked.
I think you should also refresh/update datagrid. You need to force redraw of grid.
Not sure how you insert rows. I had same problem when used DataContext.InsertOnSubmit(row), but when I just inserted rows into BindingSource instead BindingSource.Insert(Bindingsource.Count, row)
and used DataContext only to DataContext.SubmitChanges() and DataContext.GetChangeSet(). BindingSource inserts rows into both grid and context.
the answer from Atomosk helped me to solve a similar problem -
thanks a lot Atomosk!
I updated my database by the following two lines of code, but the DataGridView did not show the changes (it did not add a new row):
this.dataContext.MyTable.InsertOnSubmit(newDataset);
this.dataContext.SubmitChanges();
Where this.dataContext.MyTable was set to the DataSource property of a BindingSource object, which was set to the DataSource property of a DataGridView object.
In code it does looks like this:
DataGridView dgv = new DataGridView();
BindingSource bs = new BindingSource();
bs.DataSource = this.dataContext.MyTable; // Table<T> object type
dgv.DataSource = bs;
Setting bs.DataSource equals null and after that back to this.dataContext.MyTable did not help to update the DataGridView either.
The only way to update the DataGridView with the new entry was a complete different approach by adding it to the BindingSource instead of the corresponding table of the DataContext, as Atomosk mentioned.
this.bs.Add(newDataset);
this.dataContext.SubmitChanges();
Without doing so bs.Count; returned a smaller number as this.dataContext.MyTable.Count();
This does not make sense and seems to be a bug in the binding model in my opinion.