Not sure of the correct terminology, but is there any way to include a "coded field" that doesn't exist in the table, in an Entity Framework 5 LINQ query?
For example, in SQL you can do this:
SELECT 'Ledger' AS type, (...) FROM table
So that the query result includes a field called 'type' with the value 'Ledger'. Is there a way to do this in a LINQ query?
And before you ask why it has to be in the query, it's because the query is a union of multiple tables and I need a designation of which table the data came from. Without this I will need to query each one separately then merge them.
Yes, you can totally do this.
p.s.w.g has used something that is called an anonymous type. Basically you define the outcome of the query on the fly.
As you can see in his answer, in expression syntax this looks like Select(r => new { type = "Ledger", ... });
In query syntax it looks like this:
from xxx in y
select new { type = "Ledger" };
Behind new, there is no class / type or anything. Neither is type defined. But it will compile as a string natuarlly.
On the other hand you can define a custom ViewModel class for this
public class CustomResultVM
{
//ignoring getter and setter
public int Id;
public string type;
public string name;
}
your select would now be strongly typed and look like this:
Select(r => new CustomResultVM
{
Id = r.xxx,
type = "Ledger",
Name = r.xxxx
});
//query snytax
from xxx in y
select new CustomResultVM
{
Id = r.xxx,
type = "Ledger",
Name = r.xxxx
};
both ways are valid and it depends on what you need at any given point and time.
Sure, you can. It would look a bit like this:
var results = dbContext.Table.Select(r => new { type = "Ledger", ... });
Or if you need a named type, something like this should work:
public class UnionResult
{
string Type { get; set; }
...
}
var results = dbContext.Table.Select(r => new UnionResult { Type = "Ledger", ... });
Related
I am trying to write some code in Linq with lambda.This is my first code using lambda and i am facing an issue while updating Record.
My code is:
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias,
mfr => mfr.RPT_ID,
nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= mfr.NOTIF_ID,
RecipAdd=nr.NOTIF_RECIP_ADDR
});
foreach(var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.NotifId = "Changedxyz";
//db.SubmitChanges();
}
}
}
I am getting Error in repljoinmf_data.NotifId = "Changedxyz";
Error says: Error 2 Property or indexer 'AnonymousType#3.NotifId' cannot be assigned to -- it is read only
Can someone please help me in this.I think it is because I am using var which is anonymous but how to solve the problem.Any help is appreciated.
Thanks
As the error suggests, anonymous class instances cannot be modified once they have been projected.
Although you could switch to a strong typed class, and then reassign the member properties, however, you have an opportunity to project the desired result in the preceding LINQ statement into the same anonymous class:
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new // Anon Class projection
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= "Changedxyz", // *** No need to mutate this afterwards
RecipAdd=nr.NOTIF_RECIP_ADDR
});
Edit, Update isn't trivial assignment, suggested alternatives
Option #1 : Strongly typed Class with mutation after projection
Add a new class (I've guessed some types)
public class MyPoco
{
public int ReportId {get; set;}
public string Reportversion {get; set;}
public byte[] ReportBytes {get; set;}
public DateTime ReportDate {get; set;}
public int NotifId {get; set;}
public string RecipAdd {get; set;}
}
Which you can then project into (just specify the class name instead of anonymous):
(mfr, nr) => new MyPoco // Not anonymous
{
ReportId=mfr.RPT_ID,
...
And then do modification afterwards:
foreach(var repljoinmf_data in repljoinmf)
{
repljoinmf_data.NotifId = "SomeNewValue"
Option #2 - Create a method (or Func) which does the complex logic
Since you seem to have already materialized all the data, you are free to use complex functions in the property projections. Any of the available local variables (closure) are available to pass to thus function, as are the join lambda parameters (mfr, nr)
So for example, write a function to calculate your NotifId = "Changedxyz" replacement:
private string DoIntensiveLogic(mainframe_replication mfr, NOTIF_RECIP nr)
{
// Do Stuff
}
Which you can then use in your original anonymous projection:
(mfr, nr) => new // Anon Class projection
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= DoIntensiveLogic(mfr, nr), // Call the function each row
RecipAdd=nr.NOTIF_RECIP_ADDR
});
Anonymous types are immutable and hence created cannot be changed you have to create a new type.
To solve your issue you have to create your own type and avoid the use of anonymous type when a future update is needed.
your type may look like this
public class ReportInfo
{
public int Id{get; set;}
//the same thing for others properties
}
and your query will look like this
new ReportInfo() {
Id = mfr.RPT_ID,
Reportversion = mfr.RPT_VERS,
ReportBytes = mfr.RPT_BYTES.ToString(),
ReportDate = mfr.REPL_DTM.ToString(),
NotifId = mfr.NOTIF_ID,
RecipAdd = nr.NOTIF_RECIP_ADDR
})
than you can update easily your property
foreach(var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.NotifId = "Changedxyz";
//db.SubmitChanges();
}
More about anonymous Types
what the compiler is actually doing. When you write a line of code like this:
var o = new { property1 = expression1, ..., propertyN = expressionN };
the compiler infers the type of each expression, creates private fields of these inferred types, creates
public read-only properties for each of the fields, and creates a constructor that accepts all these
expressions. The constructor’s code initializes the private read-only fields from the expression results
passed in to it. In addition, the compiler overrides Object’s Equals, GetHashCode, and ToString
methods and generates code inside all these methods.
if you want to change 'NotifId' later, you can find a record by id and change the property.
Example:
var alias = mainframe_replication_alias.SingleOrDefault(mfr => mfr.NOTIF_ID == repljoinmf_data.NotifId);
if(alias != null)
alias.NOTIF_ID = "Changedxyz";
I have varvariable called retVal which equals to some query. After some conditions I want to equate it to another query. But I get an error like implicit cast of type "System.Collections.Generic.IEnumerable<AnonymousType#1>" in "System.Collections.Generic.IEnumerable<AnonymousType#2>" is impossible. You can ask me why I don't want to define another var variable. Because this one is used in foreach cycle. Let's have a look on the code:
var retVal = from groupItem in result.AsEnumerable()
where groupItem.Sms.First().amountOfParts == (
(from item in rawSmsList.AsEnumerable()
where item.referenceNumber == groupItem.Sms.First().referenceNumber
select item).Count()
)
select new
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
//CONDITION
if (retVal.ToArray().Length==0)
{
//HERE I NEED TO RETVAL EQUATE NEW QUERY
retVal = from groupItem in result.AsEnumerable()
where groupItem.Sms.First().amountOfParts == (
(from item in rawSmsList.AsEnumerable()
where item.senderNumber == groupItem.Sms.First().senderNumber
select item).Count()
)
select new
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
}
foreach (var item in retVal)//FOREACH EXPECTS THE SAME RETVAL!!!
So how to cast different queries to the same var variable? Or how to find type of var variable and then cast it to a new defined variable?
var means implicitly typed variable, that means its type will be determined at compile time, So on your first usage it will be assigned an anonymous type, in your second you are trying to assign it a different anonymous type, you can't do that.
You can modify your code to use a class instead of anonymous object and then project to that, then you will be to do what you are doing now. You can create the class like:
public class MyClass
{
public int Value {get;set;}
public string Sms {get;set;}
}
and then project it by modifying your select statement as:
var retVal = ......
select new MyClass
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
The anonymous class you're using for your projections looks the same to us, but they're two separate classes as far as the compiler is concerned, which is why you'll see AnonymousType#1 and AnonymousType#2 in the error.
One solution is to simply select "groupItem" instead of projecting with an anonymous class since you're only using properties within the groupItem itself. This would give you the same IQueryable type.
Side note: you should replace "retVal.ToArray().Length == 0" with "!retVal.Any()"
To add to Habib's answer:
Just create an actual class instead of using the anonymous type (which is a different class every time you use it). I don't know the types from your example so you'll have to specify:
public class ValueSmsThing // Give it a better name!
{
public IDontKnow Value { get; private set; } // specify the type!
public SmsNumber Sms { get; private set; } // !!
public ValueSmsThing( IDontKnow value, SmsNumber sms) {
Value = value;
Sms = sms;
}
}
And then in your query, instead of using the anonymous type:
select new
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
Use the concrete class you created
select new ValueSmsThing( groupItem.Value, groupItem.Sms );
Then your for loop will know to iterate over ValueSmsThings.
I am trying to build a dynamic predicate with Entity Framework by mapping an enum to the column field:
In the where clause i have entered ?? as i am not sure what to put there, i want this be dynamic like in this article, although that doesn't work me in EF on;y linq to sql:
How to specify dynamic field names in a Linq where clause?
For example:
I have an enum:
public enum SearchTypes {
FirstName = CustFName,
LastName = CustLName
}
My method is as such:
private static IEnumerable<CustomerSearchInfo> GetCustomers(String customerName, SearchType searchType)
{
using (var context = new NewgenEntities())
{
return context.tblCustomers.Where(??).
Select(p => new CustomerSearchInfo
{
FirstName = p.CustFName,
LastName = p.CustLName,
Id = p.CustID,
EmailAddress = p.CustEmail,
Mobile = p.CustMNumber,
Phone = p.CustPNumber
}).ToList();
}
Has anyone got a way of building an expression based on a enum?
Check out this post for using enums with EF. It's a lot to go through but it works.
Another approach is to create 1 property that is an enum (let's call it SearchType) and then another integer property called SearchTypeId. The enum property encapsulates the Id property like this:
public SearchType SearchType
{
get
{
return (SearchType)this.SearchTypeId;
}
set
{
this.SearchTypeId = (int)value;
}
}
Yes, this is also ugly - but it works.
In the next version of EF, it will support enums but this obviously doesn't do you too much code right now.
I am just getting my feet wet with LINQ to SQL, and need some advice in implementing a simple scenario:
I have a method ListTagCounts that is doing an aggregate query with LINQ To SQL. I was not sure of the return type to use, so used the ToList() method and created a class just for the return type in order to get it to compile.
Schema:
Link LinkTag Tag
---------- ---------- ----------
LinkID LinkID TagID
URL TagID Name
IsDeleted
Code:
static void Main(string[] args)
{
var counts = ListTagCounts();
foreach(var c in counts)
Console.WriteLine("Tag: {0}, Count: {1}", c.Tag, c.Count);
Console.ReadKey();
}
public static List<MyReturnClass> ListTagCounts()
{
List<MyReturnClass> counts;
using (var db = new MyDbDataContext())
{
counts = (from t in db.Tags
join lt in db.LinkTags on t.TagID equals lt.TagID
join l in db.Links on lt.LinkID equals l.LinkID
where l.IsDeleted == false
select new MyReturnClass() { Tag = t.Name, Count = t.LinkTags.Count() }
).Distinct().OrderBy(t => t.Tag).ToList();
}
return counts;
}
public class MyReturnClass
{
public string Tag { get; set; }
public int Count { get; set; }
}
If I do
select new { Tag = t.Name, Count = t.LinkTags.Count() }
rather than
select new MyReturnClass() { Tag = t.Name, Count = t.LinkTags.Count() }
in my LINQ query, what should the return type be?
When you use the following syntax:
select new { Tag = ..., Count = ... };
You are creating an anonymous type. The compiler generates the name of this type for you at compile-time, so there is no way for you to know what it is.
When you call ToList on the query that selects instances of this anonymous type, it's possible that you can return the list because List implements some non-generic classes (which obviously don't rely on the type parameter T, which you aren't aware of) you can cast to.
Generally though, you should not let anonymous types escape the method that they are used in. If you have the need to pass the information outside of the method that the query is in, then what you are doing is correct, in creating a specialized class and then returning a sequence of that.
Note there are some justified uses for passing anonymous types outside of your method (through a return type of object, or other base classes for sequences of these types), but for cases like this, it isn't one of them.
The first option will return an anonymous type which cannot be a return type of your method, the second way is a concrete class that holds your information, so the type is known and therefore is valid to be returned.
I would also suggest to return IEnumerable<MyReturnClass> unless you need it to be a list (read: you expect to add more items to it)
In general you'd want to assign that to the 'var' type, but that's only good for local variables. 'object' maybe??? But that's a longshot
So I have this LINQ query that ends in a custom select kinda like this:
select new { this1 = table.this1, this2 = othertable.this2 }
The call to that query from the Controller looks something like this:
ViewData["these"] = theRepo.GetAllThese(someVar, anotherVar);
Now when I pass this on to my view since it is not strongly typed how can I iterate through it with a foreach, how can I cast it as an IQueryable or a List if I don't know what's in it?
...is it something like this?
IQueryable<???> these = ViewData["These"];
foreach (var this in these) {...
Just need to know what to put for '???' I think.
You cannot use an anonymous type (select new { Property = value }) outside the scope in which it is defined. So you should use foreach(var x in {yourQueryHere}) from within the method you defined the query in.
Example:
This is possible:
public void myMethod() {
var x = from c in IEnumerable select new { Prop = value };
foreach (var y in x) {
}
}
This is impossible:
public void myMethod() {
foreach (var y in myMethod2()) {
}
}
public IQueryable<???> myMethod2() {
return from c in IEnumerable select new { Prop = value };
}
Your linq query returns a collection of anonymously typed objects. Being anonymous, there is no way to "call their name" when declaring an explicitly typed variable. Thus, the true type/shape of the objects is only known within the action method where the objects are defined.
The indexed getter of the ViewData object has a return type of object, and without knowing the type name, you want be able to cast the return value of ViewData["these"] to anything useful.
What you might want to do instead, is to create a model - more specifically a "view model" - which defines the structure of the objects you are selecting using LINQ:
public class FoobarViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
and redefine your query to do a select like this:
select new FoobarViewModel { foo = table.this1, bar = othertable.this2 }
Your objects now share a common named class, and your collection can be easily casted to the proper type in the view.