Querying for object based on property of inside object - c#

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

Related

Json.Net Deserializing list of c# objects throwing error

I have a list of objects in below json format. I would like to deserialize using below code. It is throwing unable to convert to object error. I have tried below three options, but didnt help. jsoninput is a IEnumerable<string>converted into json object using ToJson().
Error:
{"Error converting value \"{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false,\"userType\":0,\"profilePrivacy\":1,\"chatPrivacy\":1,\"callPrivacy\":0}\" to type 'Api.Models.UserInfo'. Path '[0]', line 1, position 271."}
var requests1 = JsonConvert.DeserializeObject<UsersInfo>(jsoninput);
var requests2 = JsonConvert.DeserializeObject<IEnumerable<UserInfo>>(jsoninput);
var requests3 = JsonConvert.DeserializeObject<List<UserInfo>>(jsoninput);
//Below are my classes,
public class UsersInfo
{
public List<UserInfo> UserInfoList { get; set; }
public UsersInfo()
{
UserInfoList = new List<UserInfo>();
}
}
public class UserInfo
{
public string Id { set; get; }
public string Name { set; get; }
public string LastName { set; get; }
public string ProfilePictureUrl { set; get; }
public string SmallUrl { set; get; }
public string ThumbnailUrl { get; set; }
public string Country { set; get; }
public bool IsInvalid { set; get; }
}
Below is my json object,
["{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}","{\"id\":\"318c0885-2720-472c-ba9e-1d1e120bcf65\",\"name\":\"locomotives\",\"lastName\":\"riddles\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}"]
Looping through individual items in json input and if i deserialize it like below, it works fine. But i want to deserialize the list fully. Note: jsoninput was a IEnumerable<string> before i convert in json object.
foreach (var re in jsoninput)
{
var request0 = JsonConvert.DeserializeObject<UserInfo>(re);
}
Please look at this fiddle: https://dotnetfiddle.net/XpjuL4
This is the code:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
//Below are my classes,
public class UsersInfo
{
public List<UserInfo> UserInfoList { get; set; }
public UsersInfo()
{
UserInfoList = new List<UserInfo>();
}
}
public class UserInfo
{
public string Id { set; get; }
public string Name { set; get; }
public string LastName { set; get; }
public string ProfilePictureUrl { set; get; }
public string SmallUrl { set; get; }
public string ThumbnailUrl { get; set; }
public string Country { set; get; }
public bool IsInvalid { set; get; }
}
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
Option1();
Option2();
}
public static void Option1(){
string json = #"{""UserInfoList"":[
{""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
{ ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
]}";
var obj = JsonConvert.DeserializeObject<UsersInfo>(json);
obj.UserInfoList.ForEach(e => Console.WriteLine(e.Id));
}
public static void Option2(){
string json = #"[
{""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
{ ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
]";
var obj = JsonConvert.DeserializeObject<List<UserInfo>>(json);
obj.ForEach(e => Console.WriteLine(e.Id));
}
}
Both work, and are basically very close to what you are doing. You can either serialize it as a list (based on your json, I think that's the closest to your use case, and that's Option 2).
However, put extra attention to the JSON. I had to re-parse your JSON to make it work (https://jsonformatter.org/json-parser is a nice website to do it). For the sake of explaining the example, in C#, # means raw string, and in raw string, quotes are escaped with double quotes "".
I would expect that the business logic generating this JSON is not correct, if the JSON you pasted is the direct result from it.
EDIT
Given the OP's comment:
Thanks Tu.ma for your thoughts. The other method returns
IEnumerable which is nothing but
Dictionary.Where(x => x.Value == null).Select(x =>
x.Key).ToHashSet(). The values in Dictionary are -> Key
is String, Value is UserInfo object serialized. So, in that case i
should deserialize one by one? If not, i should serialize entire list
in one shot? Am i right? – Raj 12 hours ago
The problem is in the way you are generating the list of UsersInfo. The result from Dictionary<string,string>.Where(x => x.Value == null).Select(x =>
x.Key).ToHashSet() is a bunch of strings, not of objects, so you need to serialize them one by one.
If you are worried about the linearity of the approach, you could consider running through it in parallel. Of course, you need to judge if it fits your application.
var userInfoStrings = Dictionary<string,string>.Where(x => x.Value == null).Select(x => x.Key).ToHashSet();
var UserInfoList = userInfoStrings.AsParallel().Select (u => JsonConvert.DeserializeObject<UsersInfo>(u)).ToList();

List of bools always returns false

When trying to get a list of bools to map to my properties, the list always return false for all items eventhough some of them are true. In the SQL db those columns are setup as bit, in my code these are booleans.
When I run my query directly in SQL I get the desired results, but debugging the same query in VS and looking at the output, the returned values stay false. I've manually ran an update query in the db to ensure some values are true, but still they return false. In the method I already tried to clear the list before filling it up but doesn't help.
DataAccess using Dapper:
public List<PromoLinesBPConditions> GetBlankPaperConditions()
{
using (IDbConnection connection = new
System.Data.SqlClient.SqlConnection(Helper.CnnVal(_dbNameEng)))
{
var output = connection.Query<PromoLinesBPConditions>($"SELECT
Invoice_Promo, CopyInvoice_Promo, Folio_Promo, ConfLetter_Promo,
BQTOffer_Promo, BQTPO_Promo, Reminder_Promo, ProForma_Promo,
Message_Promo from RPTSET_Invoice_Parameters").ToList();
return output;
}
}
PromoLinesBPConditions class:
public class PromoLinesBPConditions
{
public bool OnBPInvoice { get; set; }
public bool OnBPCopyInvoice { get; set; }
public bool OnBPFolio { get; set; }
public bool OnBPConfLetter { get; set; }
public bool OnBPBQTOffer { get; set; }
public bool OnBPBQTPO { get; set; }
public bool OnBPReminder { get; set; }
public bool OnBPProForma { get; set; }
public bool OnBPMessage { get; set; }
}
In the DetailViewModel:
private void GetBlankPaperConditions()
{
BlankPaperConditions = _dataService.GetBlankPaperConditions();
foreach (var item in BlankPaperConditions)
{
OnBPInvoice = item.OnBPInvoice;
OnBPCopyInvoice = item.OnBPCopyInvoice;
OnBPFolio = item.OnBPFolio;
OnBPConfLetter = item.OnBPConfLetter;
OnBPBQTOffer = item.OnBPBQTOffer;
OnBPBQTPO = item.OnBPBQTPO;
OnBPReminder = item.OnBPReminder;
OnBPProForma = item.OnBPProForma;
OnBPMessage = item.OnBPMessage;
}
}
In the database, OnBPInvoice (Invoice_Promo column) and OnBPCopyInvoice (CopyInvoice column) are true. I want to get the correct results back.
Dapper does provide out of the box mapping like EF does(with [Column("MyColumnName")]
Meaning that the class properties must be exactly as they are written in the DB
Meaning that Invoice_Promo (as in your SELECT statement) must be named
public bool Invoice_Promo{ get; set; }
If you want to can create your custom mapper and use it like so
public class MyMapper : EntityMap<MyClassName>
{
public MyMapper()
{
Map(i => i.MyPropery).ToColumn("MyCustomPropery");
}
}
and then initialized you mapper
FluentMapper.Initialize(config =>
{
config.AddMap(new MyMapper());
});
More info you can find here

New class selected by LINQ query, how to transfer to another model?

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).

How to move string into ViewModel

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()

Looping through (IEnumerable) results and updating, but nothing updated?

I am looping thru parent records ("europe") and updating its <Ienumerable> field called "childPublication" with its child records. But the childPublication is null after the loop and assignment?
Here's my code:
foreach (var e in europe)
{
string child = e.HasChild ?? "";
if (child.Contains("True"))
{
IEnumerable<Publication> eChildrens = children.OfType<Publication>()
.Where(ep => ep.ParentID.Equals(e.PublicationId));
if (eChildrens.Count() > 0)
{
e.ChildPublication = eChildrens;
}
}
}
member.EuropeMiddleEastAfricaPublication = europe;
public class Publication
{
public int PublicationId { get; set; }
public int ContentTypeId { get; set; }
public string PublicationName { get; set; }
public string PublicationFullName { get; set; }
public string ShortDescription { get; set; }
public string LongDescription { get; set; }
public string URL { get; set; }
public string CountryId { get; set; }
public string LanguageId { get; set; }
public string Active { get; set; }
public string Subscription { get; set; }
public string ClientOnly { get; set; }
public string PrintVersion { get; set; }
public string EmailVersion { get; set; }
public string RegisteredforPrint { get; set; }
public string RegisteredforEmail { get; set; }
public int ParentID { get; set; }
public string HasChild { get; set; }
public IEnumerable<Publication> ChildPublication { get; set; }
}
First, you have eChildren = children, so I'm assuming children is passed in somewhere?
I would probably code it something like:
foreach (var e in europe)
{
// .Net 4.0 use: string.IsNullOrWhiteSpace()
if (!string.IsNullOrEmpty(e.HadChild)
// I prefer IndexOf which allows Culture and IgnoreCase
&& e.HasChild.IndexOf("True", StringComparison.CurrentCultureIgnoreCase))
{
IEnumerable<Publication> eChildrens =
children.OfType<Publication>()
.Where(ep => ep.ParentID.Equals(e.PublicationId))
.ToList(); //Force the IEnumeration to Enumerate.
if (eChildrens.Count() > 0)
{
e.ChildPublication = eChildrens;
}
}
}
You should debug your program and verify that you are actually getting inside your if and setting the property. If you aren't, then it will absolutely be null. But note that you are doing something dangerous anyway by closing over the loop variable.
IEnumerable<Publication> eChildrens =
children.OfType<Publication>().Where(ep =>
ep.ParentID.Equals(e.PublicationId));
if (eChildrens.Count() > 0)
{
e.ChildPublication = eChildrens;
}
eChildrens is a lazily evaluated query and it is capturing the loop variable e. When you get outside the query and try to use the results, unless you have weird expectations, you code is not going to do what you want. In a closure, it is the variable that is captured, so your query will always be looking at the same var e when you get outside of the loop. You're going to have a lot of objects looking at the wrong ChildPublication sequences.
To avoid this issue, either create a local temporary variable inside the loop and close over that
var temp = e; // local temporary variable, used below
IEnumerable<Publication> eChildrens =
children.OfType<Publication>().Where(ep =>
ep.ParentID.Equals(temp.PublicationId));
if (eChildrens.Count() > 0)
{
e.ChildPublication = eChildrens;
}
Or alternately force evaluation of the query by invoking a method such as ToList();
IEnumerable<Publication> eChildrens =
children.OfType<Publication>().Where(ep =>
ep.ParentID.Equals(e.PublicationId)).ToList();
if (eChildrens.Count() > 0)
{
e.ChildPublication = eChildrens;
}
For more on this topic, please read Eric Lippert's blog entry.
Here is the problem. IEnumerable users an iterator run against your data source. Iterators return a new object, not a reference to the original object.
So, you are making changes on a copy of your original data, not your actual data. If you want to modify your original data, you need to pass a reference to it and work with that reference.
Have you tried using a List<Publication> instead or IEnumerable<Publication>. I always have much more sucess with it for simple collection handling. IEnumerable often times wants an Enumerator defined which is a little more overhead.

Categories