How to get more than one column in Linq - c#

here is my code:
firstAnswer = p.Answers.Select(z => z.vountcount, z.isSelected).FirstOrDefault()
In the select statement, it returns a syntax error. I am trying to get more then one column.

var firstAnswer = p.Answers.FirstOrDefault().Select(new { VountCount = z.vountcount, IsSelected = z.isSelected });
You must specify a type. Var is the keyword allowing you to instantiate an anonymous type.

You'll either have to create a type or use anonymous types to capture that result:
Anonymous types:
var firstAnswer = p.Answers.Select(z => new { vountcount = z.vountcount, isSelected = z.isSelected }).FirstOrDefault();
The explicit naming is in most cases optional.
Using the var keyword here ensures, that you can assign that anonymous result. If you want to hand that result to some method, it'll get difficult with anonymous types.
Dedicated type:
public class ReducedAnswer
{
public int vountcount { get; set; }
public bool isSelected { get; set; }
public ReducedAnswer()
{
}
}
ReducedAnswer firstAnswer = p.Answers.Select(z => new ReducedAnswer { vountcount = z.vountcount, isSelected = z.isSelected }).FirstOrDefault();
Kept it close to typical LINQ model classes and your naming. Note the use of the type in front of firstAnswer. You could go with var here as well.

Related

How to push a list of anonymous types to a list of defined types

I have an IQueryable Anonymous type being returned from a query, of the form:
EntityQueryable<<>f__AnonymousType1<g = Game, ghp = GameHasPlayer>>
I'm trying to construct a class to accept this query result so I can manipulate it easily
public class GamesWithPlayers
{
public Game game { get; set; }
public GameHasPlayer gameHasPlayer { get; set; }
}
I've managed to squish the anonymous type to something more recognisable to me by using
var anonList = x.ToList() //Where x is the IQueryable of anonymous type`
I know how to get one instance of my containing class populated like so:
GamesWithPlayers a = new GamesWithPlayers() { game = anonList[0].g, gameHasPlayer = anonList[0].ghp };
but is there a way to put the entire anonList in to a new List<GamsWithPlayers>?
I tried casting
List<GamesWithPlayers> gamesWithPlayers = (List<GamesWithPlayers>)y;
But obviously there's no assigning game = g, gameHasPlayers = ghp and I have no idea what the syntax for that'd be :/
You want to transform each element of a IEnumerable<T> to something else. This is exactly what Select does.
You have shown that given an object x of your anonymous class, you can create a GamesWithPlayers from it like this:
new GamesWithPlayers() { game = x.g, gameHasPlayer = x.ghp }
You can pass this expression to Select:
var gamesWtihPlayersList =
anonList
.Select(x => new GamesWithPlayers() { game = x.g, gameHasPlayer = x.ghp })
.ToList();
And this will be applied to each element in anonList.

Error when casting variable

I get an error when I try to cast a query. This is the code of the query:
var query = (from article in db.V_CLIENT_PRIX
where article.CLIENT == Current_Client_Id
select new
{
ID = article.ID,
ARTICLE = article.Article,
REFERENCE = article.Reference,
REMISE = article.Remise,
PRIXVHT = article.PrixVHT,
CLIENT = article.CLIENT,
}
);
And I cast it like this:
ConventionList articlelistconvention = new ConventionList();
articlelistconvention = (ConventionList)query;
This is the code of my model:ConventionList
public class Commandelist
{
public string ARTICLE { get; set; }
public string CIN { get; set; }
public decimal STOCK { get; set; }
public string REFERENCE { get; set; }
public decimal PRIXVHT { get; set; }
public string IMAGE { get; set; }
public double QUANTITE { get; set; }
}
Can someone help me fix it?
You might be coming from a language with duck typing, like Javascript; however, in C# this is not possible. You can typically only cast objects if the interfaces and/or inheritance allows you to do so. The dynamic object you create in your Linq query will not share ancestry with the object you're trying to cast to.
In your specific code example though there is a quick fix:
var query = (
from article in db.V_CLIENT_PRIX
where article.CLIENT == Current_Client_Id
select new ConventionList // < --- change here!!
{
ID = article.ID,
ARTICLE = article.Article,
REFERENCE = article.Reference,
REMISE = article.Remise,
PRIXVHT = article.PrixVHT,
CLIENT = article.CLIENT,
});
However, getting this to work exactly for your scenario might require some tweaking, as your question is ambiguous about the difference / overlap between the dynamic object, the ConventionList class, and the CommandeList class.
You need to specify your type in the SELECT.
You can't cast anonymous types to declared types
You can't cast unrelated types to each other (command / convention) unless you just slopely pasted the wrong code for us to look at / figure out)
You can't cast List<T> of one type to another type, IEnemurable could work if the generics were related because of covariance.
Updated code with an explicit type in the constructor instead of an anonymous object, again I think you meant Convention but if not change it to the type you need.
var query = (
from article in db.V_CLIENT_PRIX
where article.CLIENT == Current_Client_Id
select new Convention()
{
ID = article.ID,
ARTICLE = article.Article,
REFERENCE = article.Reference,
REMISE = article.Remise,
PRIXVHT = article.PrixVHT,
CLIENT = article.CLIENT,
});

Linq update issue with lambda

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";

How to equate `var` variable to another query

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.

Iterate through IQueryable of no specific type?

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.

Categories