Explicit construction of entity type in query is not allowed [duplicate] - windows-phone-7

Using Linq commands and Linq To SQL datacontext, Im trying to instance an Entity called "Produccion" from my datacontext in this way:
Demo.View.Data.PRODUCCION pocoProduccion =
(
from m in db.MEDICOXPROMOTORs
join a in db.ATENCIONs on m.cmp equals a.cmp
join e in db.EXAMENXATENCIONs on a.numeroatencion equals e.numeroatencion
join c in db.CITAs on e.numerocita equals c.numerocita
where e.codigo == codigoExamenxAtencion
select new Demo.View.Data.PRODUCCION
{
cmp = a.cmp,
bonificacion = comi,
valorventa = precioEstudio,
codigoestudio = lblCodigoEstudio.Content.ToString(),
codigopaciente = Convert.ToInt32(lblCodigoPaciente.Content.ToString()),
codigoproduccion = Convert.ToInt32(lblNroInforme.Content.ToString()),
codigopromotor = m.codigopromotor,
fecha = Convert.ToDateTime(DateTime.Today.ToShortDateString()),
numeroinforme = Convert.ToInt32(lblNroInforme.Content.ToString()),
revisado = false,
codigozona = (c.codigozona.Value == null ? Convert.ToInt32(c.codigozona) : 0),
codigoclinica = Convert.ToInt32(c.codigoclinica),
codigoclase = e.codigoclase,
}
).FirstOrDefault();
While executing the above code, I'm getting the following error that the stack trace is included:
System.NotSupportedException was caught
Message="The explicit construction of the entity type 'Demo.View.Data.PRODUCCION' in a query is not allowed."
Source="System.Data.Linq"
StackTrace:
en System.Data.Linq.SqlClient.QueryConverter.VisitMemberInit(MemberInitExpression init)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitFirst(Expression sequence, LambdaExpression lambda, Boolean isFirst)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node)
en System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
en System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
en System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
en System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
en Demo.View.InformeMedico.realizarProduccionInforme(Int32 codigoExamenxAtencion, Double precioEstudio, Int32 comi) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 602
en Demo.View.InformeMedico.UpdateEstadoEstudio(Int32 codigo, Char state) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 591
en Demo.View.InformeMedico.btnGuardar_Click(Object sender, RoutedEventArgs e) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 683
InnerException:
Is that now allowed in LINQ2SQL?

Entities can be created outside of queries and inserted into the data store using a DataContext. You can then retrieve them using queries. However, you can't create entities as part of a query.

I am finding this limitation to be very annoying, and going against the common trend of not using SELECT * in queries.
Still with c# anonymous types there is a workaround, by fetching the objects into an anonymous type, and then copy it over into the correct type.
For example:
var q = from emp in employees where emp.ID !=0
select new {Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.ToList();
List<User> users = new List<User>(r.Select(new User
{
Name = r.Name,
EmployeeId = r.EmployeeId
}));
And in the case when we deal with a single value (as in the situation described in the question) it is even easier, and we just need to copy directly the values:
var q = from emp in employees where emp.ID !=0
select new { Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.FirstOrDefault();
User user = new User { Name = r.Name, EmployeeId = r.ID };
If the name of the properties match the database columns we can do it even simpler in the query, by doing select
var q = from emp in employees where emp.ID !=0
select new { emp.First, emp.Last, emp.ID }
One might go ahead and write a lambda expression that can copy automatically based on the property name, without needing to specify the values explictly.

Here's another workaround:
Make a class that derives from your LINQ to SQL class. I'm assuming that the L2S class that you want to return is Order:
internal class OrderView : Order { }
Now write the query this way:
var query = from o in db.Order
select new OrderView // instead of Order
{
OrderID = o.OrderID,
OrderDate = o.OrderDate,
// etc.
};
Cast the result back into Order, like this:
return query.Cast<Order>().ToList(); // or .FirstOrDefault()
(or use something more sensible, like BLToolkit / LINQ to DB)
Note: I haven't tested to see if tracking works or not; it works to retrieve data, which is what I needed.

I have found that if you do a .ToList() on the query before trying to contruct new objects it works

I just ran into the same issue.
I found a very easy solution.
var a = att as Attachment;
Func<Culture, AttachmentCulture> make =
c => new AttachmentCulture { Culture = c };
var culs = from c in dc.Cultures
let ac = c.AttachmentCultures.SingleOrDefault(
x => x.Attachment == a)
select ac == null ? make(c) : ac;
return culs;

I construct an anonymous type, use IEnumerable (which preserves deferred execution), and then re-consruct the datacontext object. Both Employee and Manager are datacontext objects:
var q = dc.Employees.Where(p => p.IsManager == 1)
.Select(p => new { Id = p.Id, Name = p.Name })
.AsEnumerable()
.Select(item => new Manager() { Id = item.Id, Name = item.Name });

Within the book "70-515 Web Applications Development with Microsoft .NET Framework 4 - Self paced training kit", page 638 has the following example to output results to a strongly typed object:
IEnumerable<User> users = from emp in employees where emp.ID !=0
select new User
{
Name = emp.First + " " + emp.Last,
EmployeeId = emp.ID
}
Mark Pecks advice appears to contradict this book - however, for me this example still displays the above error as well, leaving me somewhat confused. Is this linked to version differences? Any suggestions welcome.

I found another workaround for the problem that even lets you retain your result as IQueryale, so it doesn't actually execute the query until you want it to be executed (like it would with the ToList() method).
So linq doesn't allow you to create an entity as a part of query? You can shift that task to the database itself and create a function that will grab the data you want. After you import the function to your data context, you just need to set the result type to the one you want.
I found out about this when I had to write a piece of code that would produce a IQueryable<T> in which the items don't actually exist in the table containing T.

pbz posted a work around by creating a View class inherited from an entity class that you could be working with. I'm working with a dbml model of a table that has > 200 columns. When I try and return the whole table I get "Root Element missing" errors. I couldn't find anyone who wanted to deal with my particular issue so I was looking at rewriting my entire approach. Just creating a view class for the entitiy class worked in my case.
As pbz suggests : Create a view class that inherits from your entity class. For me this is tbCamp so :
internal class tbCampView : tbCamp
{
}
Then use the view class in your query :
using (var dc = ConnectionClass.Connect(Dev))
{
var camps = dc.tbCamps.Select(s => new tbCampView
{
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
SmartTableViewer(camps, dg1);
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
Here is what happens when you try and create an entity class object in the query.
I didn't want to have to use an anonymous type if I could help it because I wanted the type to be tbCamp. Since tbCampView is of type tbCamp the is operator works well. see Brian Hasden's answer Passing a generic List<> in C#
I'm surprised this is even an issue but with larger tables I run into this error so I thought I would just show it here :
When trying to read this table into memory I get the following error. There are < 2000 rows but the columns are > 200 for each. I don't know if that is an issue or not.
If I just want a few columns I need to create a custom class and handle that which isn't that big of a pain. With the approach pbz provided I don't have to worry about it.
Here is the entire project in case it helps someone.
public partial class Form1 : Form
{
private const bool Dev = true;
public Form1()
{
InitializeComponent();
}
private void btnGetAllCamps_Click(object sender, EventArgs e)
{
using (var dc = ConnectionClass.Connect(Dev))
{
IQueryable<tbCampView> camps = dc.tbCamps.Select(s => new tbCampView
{
// Project columns as needed.
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
// pass in as a
SmartTableViewer(camps);
}
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
//var newRecord = record;
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
internal class tbCampView : tbCamp
{
}
}

Related

Linq in C# using IEnumerable

Appearently, I got an error if using the following code. It said:
Cannot implicity converrt type System.Linq.IQueryable<AnonymousType> to System.Collection.Generic.IEnumerable.
Please advise how I can fix this?
public IEnumerable<Session> GetAllListDetailConsumer(string refId)
{
ObjectQuery<Session> sessions = db.Sessions;
ObjectQuery<SessionsList> sessionsLists = db.SessionsList;
var query =
from s in sessions
join sList in sessionsLists on s.ReferralListID equals sList.ReferralListID
where s.ReferralListID == new Guid(refId)
select new SessionConsumerList
{
ReferralListID = s.ReferralListID,
SessionServerId = s.SessionServerID,
ApplicationID = s.ApplicationID,
// ...
ConsumerID = sList.ConsumerID,
ConsumerFirstName = sList.ConsumerFirstName,
ConsumerFamilyName = sList.ConsumerFamilyName,
// ...
};
return query.ToList();
}
You are selecting using select new, which would create an anonymous type, you need to project to class Session in your query like.
select new Session
{
....
But remember if your Session class is a representing a table in your database/data context, then you can't project to that class, instead you may have to create a temporary class and project the selection to that class.
EDIT (Since the question now has been edited)
Now you are selecting new SessionConsumerList and you are returning IEnumerable<Session>, you need to modify method signature to return IEnumerable<SessionConsumerList>
Why not separate the creation of the SessionConsumerList in another method? Makes the code a lot cleaner. Like this:
public static SessionConsumerList CreateSessionConsumerList(
Session s,
SessionsList sList)
{
return new SessionConsumerList
{
ReferralListID = s.ReferralListID,
SessionServerId = s.SessionServerID,
ApplicationID = s.ApplicationID,
// ...
ConsumerID = sList.ConsumerID,
ConsumerFirstName = sList.ConsumerFirstName,
ConsumerFamilyName = sList.ConsumerFamilyName,
// ...
};
}
And then:
var query =
from s in sessions
join sList in sessionsLists on s.ReferralListID equals sList.ReferralListID
where s.ReferralListID == new Guid(refId)
select CreateSessionConsumerList(s, sList);

How can I call a Linq-to-Entities (EF4) query specifying a different table name dynamically?

I have a bunch of tables that all have a field called ResourceID that are populated from an outside process. I want to go through each table and validate that ID against a master list. The code is simple but gets repetitive:
var resList = (from r in dc.ResourceMasterEntities select r.ResourceId).ToList();
var res = (from rs in resList select (int?)rs).ToList();
var stage = (from s in dc.TableOne select s.ResourceId).ToList();
foreach (var invalidResourceID in stage.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID );
}
stage = (from s in dc.TableTwo select s.ResourceId).ToList();
foreach (var invalidResourceID in stage.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID );
}
// more of the same with different tables
I would like to create a function where I can pass in the name of the table (TableOne, TableTwo, etc) and not have to write all of this repetitive code. Can this be done with Linq? (and preferably not using ExecuteQuery :-))
You can create a function that takes an IQueryable as a parameter.
The function would look like:
private void CheckTable(IQueryable<EntityType> table)
{
var stage = (from s in table select s.ResourceId).ToList();
foreach (var invalidResourceID in stage.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID);
}
}
// Execute the function like:
CheckTable(dc.TableOne);
You can choose if you make errList and res class level properties or if you pas them as parameters to the function
With some modification I was able to get this to work - I had to use the built in dynamic linq to select the property that I wanted.
private void CheckTable(System.Data.Objects.ObjectSet<EntityType> table)
{
var records = table.Select("BusinessEntityNbr").ToList();
var values = (from r in records select (int?)r[0]).ToList();
foreach (var invalidResourceID in values.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID);
}
}
You may want to consider using entity SQL and DbDataRecord for unknown result types. See the Entity SQL samples in http://archive.msdn.microsoft.com/EFQuerySamples for some ideas on how to use Entity SQL.

generic method to search for an LINQ entity based on its type

partial void UpdateDenomLimit(DenomLimit instance)
{
var oldData = DataClassesDataContext.DenomLimits.Where(b => b.ID == instance.ID).First();
//Code that logs the audit when instance and oldData is passed to it
LogAudit(oldData, instance);
//Code that updates the instance
this.ExecuteDynamicUpdate(instance);
}
Above is a method for updating an instance of DenomLimit in the database.
I am logging an audit of what changes are done to the entity. For that I get the previous state of the instance by the following code and it works fine:
var oldData = DataClassesDataContext.DenomLimits.Where(b => b.ID == instance.ID).First();
now I need a generic LINQ query which can fetch the oldData when three parameters are passed to it:
1. an instance of any type
2. A primary key column name
3. A value of primary key column for the passed instance.
...so that I can keep that code in the LogAudit and then do not need to fetch in every function.
A LINQ query which will possibly look like:
var oldData = DataClassesDataContext.GetTable<instance>().Where("b => b." + colName + " == #0", new object[] { id }).First();
The full namespace is used here to indicate the namespace that it came from to make it easier to incorporate into your code.
public T GetFirstOrDefault<T>(System.Linq.Expressions.Expression<Func<T, bool>> func) where T : class
{
DataClassesDataContext.ObjectContext.CreateObjectSet<T>().FirstOrDefault(func);
// For EF 4.1 Code First
//return (ctx as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.CreateObjectSet<T>().FirstOrDefault(func);
// or
//return ctx.Set<T>().FirstOrDefault(func);
}
In this case using an Expression of a Func allows EF to figure out what data you are looking for.
Here is an example of how it would be used:
var a1 = GetFirstOrDefault<DenomLimits>(p => p.ID == oldData.ID);
var a2 = GetFirstOrDefault<DenomLimits>(p => p.OtherID == 5);

linq: Using methods in select clause

I'm breaking my head with this and decided to share my problem with you
I want to create an anonymous select from several tables, some of them may contain more than one result. i want to concatenate these results into one string
i did something like this:
var resultTable = from item in dc.table
select new
{
id= item.id,
name= CreateString((from name in item.Ref_Items_Names
select name.Name).ToList()),
};
and the CreateString() is:
private string CreateString(List<string> list)
{
StringBuilder stringedData = new StringBuilder();
for (int i = 0; i < list.Count; i++)
{
stringedData.Append(list[i] + ", ");
}
return stringedData.ToString();
}
my intentions were to convert the "name" query to list and then sent it to CreateString() to convert it to one long concatenated string.
I tried using .Aggregate((current,next) => current + "," + next);
but when i try to convert my query to DataTable like below:
public DataTable ToDataTable(Object query)
{
DataTable dt = new DataTable();
IDbCommand cmd = dc.GetCommand(query as IQueryable);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = (SqlCommand)cmd;
cmd.Connection.Open();
adapter.Fill(dt);
cmd.Connection.Close();
return dt;
}
I'm getting exception that "dc.GetCommand()" can't understand query with Aggregate method
later I tried to even use this simple query:
var resultTable = from itemin dc.table
select new
{
name = CreateString()
};
When CreateString() returns "success", nothing was inserted to "name"
why there is no way of using methods in select clause?
Thank you
Yotam
There is difference between LINQ to objects and LINQ to some-db-provider. Generally speaking, when using IQueryable, you can't use any methods, except the ones your provider understands.
What you can do is to retrieve the data from the database and then do the formatting using LINQ to objects:
var data = from item in dc.table
where /* some condition */
select item;
var result = from item in data.AsEnumerable()
select new
{
name = SomeFunction(item)
}
The AsEnumerable() extension method forces processing using LINQ to objects.
Forgive me if I've miss interpreted your question. It seems that what you are trying to do is abstract your select method for reuse. If this is the case, you may consider projection using a lambda expression. For example:
internal static class MyProjectors
{
internal static Expression<Func<Object1, ReturnObject>> StringDataProjector
{
get
{
return d => new Object1()
{
//assignment here
}
}
}
}
Now you can select your datasets as such:
dc.Table.Select(MyProjectors.StringDataProjector)
As for the concatenation logic, what about selecting to some base class with an IEnumerable<string> property and a read-only property to handle the concatenation of the string?

Subsonic Single WHERE clause

Is it possible to apply a WHERE clause on a SubSonic query?
For example, I get get a single based on id...
db.Single<Storage>(id);
But how can I get a single based on a simple WHERE clause?
db.Single<Storage>(WHERE columnname == "value");
that's possible:
// Will return a Storage instance with property IsNew = true, if record does not exist
// since an object created with new never can be null
var storage1 = new Storage(1); // id = 1
var storage1 = new Storage(Storag.Columns.ColumnName, "value");
// Will return 0 if record not found (subsonic3 only)
var storage3 = (from s in Storage
where s.ColumnName == "value"
select s).SingleOrDefault();
// Will throw an exception if record not found (subsonic3 only)
var storage3 = (from s in Storage
where s.ColumnName == "value"
select s).Single();
Since db is a partial class you can extend it. Just create a new File within the same namespace (but another folder in your solution). This applies to subsonic 2 but will be similar to subsonic 3, I think.
public static partial class DB
{
public static T Single<T>(String columName, Object columnValue) where T: RecordBase<T>, new()
{
return Select().From<T>()
.Where(columnName).IsEqualTo(columnValue)
.ExecuteSingle<T>();
}
}
Thanks for the above, this was a help and eventually I simplified this to the below...
db.Single<Storage>(s => s.ColumnName == "value");

Resources