I am creating a new ViewModel that tally's up the results of a survey, performers some calculations on that data, and then returns the new calculation to a view. I cannot figure out how to include regular "string" data in the collection.
var data = from SurveyResponseModel in db.SurveyResponseModels
group SurveyResponseModel by SurveyResponseModel.MemberId into resultCount
select new ResultsViewModel()
{
MemberId = resultCount.Key,
UseNewTreatmentResult = db.SurveyResponseModels.Count(r => r.UseNewTreatment),
UseBetterTechniqueResult = db.SurveyResponseModels.Count(r => r.UseBetterTechnique),
ChangesOthersResult = db.SurveyResponseModels.First(r => r.ChangesOthers),
};
return View(data);
The first part is counting boolean responses and passing them as an integer back to the ViewModel. The section that includes ChangesOthersResult = db.SurveyResponseModels.First(r => r.ChangesOthers), Should just select the strings from the Model and pass to the ViewModel. I am currently getting a syntax error about changing from type string to bool. I'm not sure what the syntax for this is.
public class SurveyResponseModel
{
[Key]
public int ResponseId { get; set; }
public int MemberId { get; set; }
public int ProgramId { get; set; }
[DisplayName("Use a new treatment")]
public bool UseNewTreatment { get; set; }
[DisplayName("Use better/more updated technique")]
public bool UseBetterTechnique { get; set; }
[DisplayName("Other (please specify):")]
public string ChangesOthers { get; set; }
}
public class ResultsViewModel
{
public int MemberId { get; set; }
public int ProgramId { get; set; }
[DisplayName("Use a new treatment")]
public int UseNewTreatmentResult { get; set; }
[DisplayName("Use better/more updated technique")]
public int UseBetterTechniqueResult { get; set; }
[DisplayName("Other (please specify):")]
public string ChangesOthersResult { get; set; }
}
You need:
ChangesOthersResult = db.SurveyResponseModels.Select(r => r.ChangesOthers)
Or SelectMany. Eventually add FirstOrDefault() at the end depending on what type ChangesOthersResult is and what you actually want to select.
Select gives you a "collection of collections" (I am assuming that ChangesOthers is a collection type). SelectMany a "flattened collection" of the generic type of your ChangesOthers collection. Adding FirstOrDefault() after Select gives you the single collection of the first SurveyResponseModels entity - or null.
Edit
After you supplied the classes I see that ChangesOthers and ChangesOthersResult aren't collections but just of type string. So the line should be:
ChangesOthersResult = db.SurveyResponseModels.Select(r => r.ChangesOthers)
.FirstOrDefault()
Related
here is my setup.
Base Model
public class Base
{
public int BaseID { get; set; }
[StringLength(8)]
[Index(IsUnique = true)]
public string BaseNumber { get; set; }
public ICollection<BillOfMaterial> billOfMaterials { get; set; }
}
BillOfMaterial Model
public class BillOfMaterial
{
public int BillOfMaterialID { get; set; }
[StringLength(10)]
[Index(IsUnique = true)]
public string BomNumber { get; set; }
public ICollection<Base> Bases { get; set; }
}
What I am trying to do is select all bill of material BomNumbers where the base is equal to a input base number.
What I have tried
BaseNumber = "A1C1D001";
var BOMQuery = (from Base in db.Bases.Include("BillOfMaterials")
where Base.BaseNumber == BaseNumber
select Base.billOfMaterials.ToList());
When trying to create this query I can't see the BomNumber property when I do => select Base.BillOfMaterials.(Can't Find Property)
I tried using the .Include() extension to try and bring in the related table in hopes it would give me the property. Not sure how to word this question exactly to do a good google search for the answer. What am I doing wrong here? Any help would be appreciated.
Thank you,
When you only need a list of BOMs use the following:
var BOMQuery = db.Bases
.Where(x => x.BaseNumber == BaseNumber)
.SelectMany(a => a.billOfMaterials.Select(b => b.BomNumber)).ToList();
You can then add it to an ObservableCollection like this:
BomList = new ObservableCollection<string>(BOMQuery);
I'm really not understanding this as I've only dabbled in MVC and C#. I apologize if my terminology is wrong or confusing, I will do my best to answer questions. I have a couple models like so:
public class DataSharingModels
{
public string ReferenceID { get; set; }
public NBTC NBTCGroup { get; set; }
public Contractors ContractorsGroup { get; set; }
public Coordinators CoordinatorsGroup { get; set; }
public NGO NGOGroup { get; set; }
public Public PublicGroup { get; set; }
public SelectList FA_RA_List { get; set; }
}
public class NBTC
{
public String NBTC_FA_Centroid { get; set; }
public String NBTC_FA_Bound { get; set; }
public String NBTC_RA_Centroid { get; set; }
//more properties...
}
The DataSharingModels class contains the public NBTC NBTCGroup property. It is not public List<NBTC> NBTCGroup because there will only be one produced per instance of the controller being hit.
Now in my controller, I have a LINQ statement that selects a new NBTC class:
var nbtcVals = (from ds in db.SharingPermissions
where ds.FocalRefID.ToString() == ReferenceID
&& ds.ShareGroup == "NBTC"
select new NBTC
{
NBTC_FA_Centroid = ds.CIP_FA_Centroid,
NBTC_FA_Bound = ds.CIP_FA_Boundary,
NBTC_RA_Centroid = ds.CIP_RA_Centroid,
//more properties...
});
Where I'm going wrong is I would like to add that to my DataSharingModels model. I thought the nbtcVals type would be NBTC, but it's IQueryable<##.Models.NBTC>. I understand I could do this, but it seems redundant:
DataSharingModels dsm = new DataSharingModels();
if (nbtcVals.Any())
{
foreach (var i in nbtcVals)
{
dsm.NBTCGroup.NBTC_FA_Centroid = i.NBTC_FA_Centroid;
dsm.NBTCGroup.NBTC_FA_Boundary = i.NBTC_FA_Bound;
dsm.NBTCGroup.NBTC_RA_Centroid = i.NBTC_RA_Centroid;
//more properties...
}
}
What is a more direct way to do this? There must be one. I supposed I could also return an anonymous type in the LINQ query and then assign each property in the foreach like dsm.NBTCGroup.NBTC_RA_Centroid = i.NBTC_RA_Centroid but that seems the same as the other way.
var nbtcgroup = (from ds in db.SharingPermissions
where ds.FocalRefID.ToString() == ReferenceID
&& ds.ShareGroup == "NBTC"
select new NBTC
{
NBTC_FA_Centroid = ds.CIP_FA_Centroid,
NBTC_FA_Bound = ds.CIP_FA_Boundary,
NBTC_RA_Centroid = ds.CIP_RA_Centroid,
//more properties...
})
.OrderByDescending(n => n.Id) // or some other property that could identify sorting
.FirstOrDefault();
This one has a translation to SQL (LIMIT or TOP depending on backend).
I have some objects stored in a LiteDB database. I'm trying to get a result of all CostBasisTradeSessionObjects that include Marked objects with a particular name, MarkedNameString. I find the Marked object easily enough, but I dont now how to query for object in object.
public string Marked
{
public ObjectId MarkedId { get; set; }
public String Name { get; set; }
}
public class CostBasisTradeSessionObject
{
public ObjectId CostBasisTradeSessionId { get; set; }
public bool IsActive { get; set; }
public DateTime SessionStarted { get; set; }
public DateTime SessionClosed { get; set; }
public Marked Marked { get; set; }
}
using (var db = new LiteDatabase(#"CostBasesTradeSessionsDatabase.db"))
{
var costBasisTradeSessionObjects = db.GetCollection("costBasisTradeSessionObjects");
Marked marked = db.GetCollection<Marked>("markeds").Find(Query.EQ("Name", "<MarkedNameString>")).Single();
}
So I try to get an result with CostBasisTradeSessionObject objects that includes the marked object returned in var marked.
So I tried a couple of things
var cb = costBasisTradeSessionObjects.Include(x => x.Marked).Equals(marked);
and justing jusing the MarkedNameString directory
var results = costBasisTradeSessionObjects.(Query.("Marked.name", "MarkedNameString"));
or
var results = costBasisTradeSessionObjects.Find(x => x.Marked.Name.Equals("MarkedNameString"));
but all the things I tried return an empty result or dont work.
Regards
I believe you're looking for the Where() method. You can filter your search by your Name property, and return an IEnumerable of CostBasisTradeSessionObject.
var results = costBasisTradeSessionObjects
.Where(x => x.Marked.Name == "MarkedNameString");
I have two classes - Record and RecordModified
public class Record
{
public int RecordID { get; set; }
public int FacilityID { get; set; }
public int NewAID { get; set; }
public string OldID { get; set; }
public string Data { get; set; }
public int SyncStatusID { get; set; }
public int RecordTypeID { get; set; }//RecordTypeID is integer here.
}
The second class
public class RecordModified
{
public int RecordID { get; set; }
public int FacilityID { get; set; }
public int NewAID { get; set; }
public string OldID { get; set; }
public string Data { get; set; }
public int SyncStatusID { get; set; }
public string RecordTypeText { get; set; }//RecordTypeText is string here.
}
I have a list of Record with at least 100 Record objects, now I have to convert the List<Record> into List<RecordModified>. The RecordTypeID property of the Record class has to be converted to the property RecordTypeText of RecordModified using enums which are in a different class.
Code snippet on how I'm trying to convert:
foreach(Record r in List<Record>)
{
switch(r.RecordTypeID)
{
case (int)MyEnum.One:
listofRecordModified.Add(new RecordModified{RecordTypeID=r.RecordTypeID,...,**RecordTypeText=(MyEnum.One).ToString()})** // Notice this
break;
...........//75 more cases.
}
This solution works fine, but the problem is lot of codes and I don't think its efficient. There must be some better way to do that. Please suggest.
I think you can use ConvertAll Method along with this
List<Record> t = new List<Record>();
var result = t.ConvertAll(x => new RecordModified()
{
RecordTypeText = ((MyEnum)x.RecordTypeID).ToString()
});
If your sole problem is the conversion of the index of an enum to its text, you could use GetNames and use the index of the to get the name of the enum value used.
string text = Enum.GetNames(typeof(MyEnum))[r.RecordTypeID];
This way, you don't need the switch statement, and you can revert to one line only.
You can just use the You can do using the (MyEnum)x.RecordTypeID to cast the integer value to matching enum value. and then use that .ToString() to get string value.Linq Lambda expressions as below,
var result = RecordList.Select(x=>new RecordModified{
RecordTypeID=x.RecordTypeID,
...,
RecordTypeText=((MyEnum)x.RecordTypeID).ToString()
});
You can also use the ConvertAll as,
var result = RecordList.ConvertAll(x => new RecordModified()
{
RecordTypeText = ((MyEnum)x.RecordTypeID).ToString()
});
Select is a LINQ extension method and works on all IEnumerable<> objects whereas ConvertAll is implemented only by List<>. The ConvertAll method exists since .NET 2.0 whereas LINQ was introduced with 3.5.
You should favor Select over ConvertAll as it works for any kind of list, but they do the same basically.
I believe you have each switch statement for each MyEnum value?
That is a lot of repeated code, that's true.
Why don't you just convert int to text value directly?
You can do it like this for more readability
foreach(Record r in List<Record>)
{
MyEnum myEnum = (MyEnum)r.RecordTypeID;
string stringValue = myEnum .ToString();
listofRecordModified.Add(new RecordModified{RecordTypeID=r.RecordTypeID, ...,**RecordTypeText=stringValue })** // Notice this
}
My data is having following structure
public enum ParamType
{
Integer=1,
String=2,
Boolean=3,
Double=4
}
public class Gateway
{
public int _id { get; set; }
public string SerialNumber { get; set; }
public List<Device> Devices { get; set; }
}
public class Device
{
public string DeviceName { get; set; }
public List<Parameter> Parameters { get; set; }
}
public class Parameter
{
public string ParamName { get; set; }
public ParamType ParamType { get; set; }
public string Value { get; set; }
}
I filled 10 document objects of Gateway in a MongoDB database.
Now I want to query all those gateways which contains a device having Parameter with ParamName as "Target Temperature" and whose Value > 15.
I created following queries
var parameterQuery = Query.And(Query<Parameter>.EQ(p => p.ParamName, "Target Temperature"), Query<Parameter>.GT(p => int.Parse(p.Value), 15));
var deviceQuery = Query<Device>.ElemMatch(d => d.Parameters, builder => parameterQuery);
var finalQuery = Query<Gateway>.ElemMatch(g => g.Devices, builder => deviceQuery);
But when I run this, it is giving an exception
Unable to determine the serialization information for the expression: (Parameter p) => Int32.Parse(p.Value)
Please suggest where I am wrong.
As the error suggests, you can't use Int32.Parse inside your query. This lambda expression is used to get out the name of the property and it doesn't understand what Int32.Parse is.
If you are querying a string, you need to use a string value for comparison:
var parameterQuery = Query.And(Query<Parameter>.EQ(p => p.ParamName, "Target Temperature"), Query<Parameter>.GT(p => p.Value, "15"));
However, that's probably not what you want to do since you're using GT. To be treated as a number for this comparison you need the value to actually be an int in mongo, so you would need to change the type of your property:
public class Parameter
{
public string ParamName { get; set; }
public ParamType ParamType { get; set; }
public int Value { get; set; }
}
var parameterQuery = Query.And(Query<Parameter>.EQ(p => p.ParamName, "Target Temperature"), Query<Parameter>.GT(p => p.Value, 15));
Summary
I ran into this when I was modifying a list. It appears that Linq First/FirstOrDefault was not handled well by MongoDB for me. I changed to be an array index var update = Builders<Movie>.Update.Set(movie => movie.Movies[0].MovieName, "Star Wars: A New Hope"); Note: This is in Asp.Net 5 using MongoDB.Driver 2.2.0.
Full Example
public static void TypedUpdateExample() {
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("test");
var collection = database.GetCollection<Movie>("samples");
//Create some sample data
var movies = new Movie {
Name = "TJ",
Movies = new List<MovieData>
{
new MovieData {
MovieName = "Star Wars: The force awakens"
}
}
};
collection.InsertOne(movies);
//create a filter to retreive the sample data
var filter = Builders<Movie>.Filter.Eq("_id", movies.Id);
//var update = Builders<Movie>.Update.Set("name", "A Different Name");
//TODO:LP:TSTUDE:Check for empty movies
var update = Builders<Movie>.Update.Set(movie => movie.Movies[0].MovieName, "Star Wars: A New Hope");
collection.UpdateOne(filter, update);
}
public class Movie {
[BsonId]
public ObjectId Id { get; set; }
public string Name { get; set; }
public List<MovieData> Movies { get; set; }
}
public class MovieData {
[BsonId]
public ObjectId Id { get; set; }
public string MovieName { get; set; }
}