Querying a nested list using linq - c#

I am a beginner learning linq. How to query a list object using linq
var dbUserSettings = new List<UserSetting> {
new UserSetting {
UserId = "abcxyz#123",
Applications = new List<Application> {
new Application {
ApplicationID = "application123",
ApplicationName = "ProtocolArchiving",
Settings = new List<Setting> {
new Setting {
SettingId = "setting123",
SettingKey = "RefreshInterval",
SettingValue = "20",
IsActive = "true",
UpdatedOn = "2017-06-22",
SettingLabel = "PageRefresh" } } } } },
new UserSetting {
UserId = "abcxyz#345",
Applications = new List<Application> {
new Application {
ApplicationID = "application345",
ApplicationName = "ProtocolArchiving",
Settings = new List<Setting> {
new Setting {
SettingId = "setting456",
SettingKey = "UploadSetting",
SettingValue = "20",
IsActive = "true",
UpdatedOn = "2017-06-22",
SettingLabel = "Upload" } } } } },
new UserSetting {
UserId = "abcxyz#567",
Applications = new List<Application> {
new Application {
ApplicationID = "application678",
ApplicationName = "ProtocolArchiving",
Settings = new List<Setting> {
new Setting {
SettingId = "setting789",
SettingKey = "DownloadSetting",
SettingValue = "20",
IsActive = "true",
UpdatedOn = "2017-06-22",
SettingLabel = "Download" } } } } }
};
var response = dbUserSettings.Where(e => e.UserId == userID)
.Select(dbsetting => new UserSettingViewModel
{
SettingKey = dbsetting.Applications.Single<Setting>(s=> s == )
})
.ToArray();
I am querying for settingkey which matches with my userID.
Edit:
Missed couple of things to mention. I have tried few things here
SettingKey = dbsetting.Applications.FirstOrDefault().Select(sk => sk.Settings.FirstOrDefault()?.SettingKey);
The error is as below
My application class looks like this.
public class Application
{
public string ApplicationID { get; set; }
public string ApplicationName { get; set; }
public List<Setting> Settings { get; set; }
}

As you´re just interested in the one and only Application for every UserSetting I suppose you need this:
var response = dbUserSettings.Where(e => e.UserId == userID)
.Select(dbsetting => new UserSettingViewModel
{
SettingKey = dbsetting.Applications.FirstOrDefault()?.Settings.FirstOrDefault()?.SettingKey
};
This will just return the very first (and probably only) Setting within the very first (and propbably also only) Application within every UserSetting. If any of the lists in between in empty (either Applications or Settings) the SettingKey will be null.

Related

LINQ query to get all data about object which is collection of objects when each item of collection has own collection

Could anyone give me a hint on how to resolve the next task?
I have such a classes structure
public class Test
{
public string Title { get; set; }
public ICollection<Question> Questions { get; set; }
}
public class Question
{
public string Description { get; set; }
public ICollection<AnswerItem> AnswerItems { get; set; }
}
public class AnswerItem
{
public string Defenition { get; set; }
public bool IsCorrect { get; set; }
}
After fetching the [Test] entity from DB I've got IQueryable<Test>. And further, I wonder how to get all Question entities (as a list) with all info where each Question item would have all info about AnswerItem collection.
I have tried the next query, but it returns only a collection of all answers:
var questList = test.SelectMany(t => t.Questions.SelectMany(q => q.AnswerItems)).ToList();
And I need something like this:
Questions = new List<Question>
{
new Question
{
Name = "Question_1",
AnswerItems = new List<AnswerItem>
{
new AnswerItem { Name = "answer_1", IsCorrect = false },
new AnswerItem { Name = "answer_2", IsCorrect = false }
}
},
new Question
{
Name = "Question_2",
AnswerItems = new List<AnswerItem>
{
new AnswerItem { Name = "answer_1", IsCorrect = false },
new AnswerItem { Name = "answer_2", IsCorrect = false }
}
}
}
Your query should looks like the following one:
var query =
from t in ctx.Tests
from q in t.Questions
select new
{
Name = q.Description,
AnswerItems = q.AnswerItems.Select(a => new
{
Name = a.Defenition,
IsCorrect = a.IsCorrect
})
.ToList()
}
};
var result = query.ToList();

how I can limit the call to only one time for method "utilities.DecryptStringFromBase64String"

I am getting credential data from one of web service call and while decrypt it, the format is "username:::password". I have other class as well and finally I am creating Data class like below,
var lstStudents = new List<Student>
{
new Student
{
Name = "studen1",
Credentials = new List<Credential> {new Credential {Key = "N1", Cred = "pNn/B3yUB+x2yiC310efoAjb8EkNhH1oD3NYF0v5SNxUKPtOtpxL21saVJGjmYPi" }, new Credential { Key = "N2", Cred = "" }}
},
new Student
{
Name = "studen2",
Credentials = new List<Credential> {new Credential {Key = "N1", Cred = "PT7CpnUcG7DIrJTxN8CcqoHAyTbNNST3DzGLpGQUHF6/jyooYKW1puXb/a+WX2M8" }, new Credential { Key = "N2", Cred = "" }}
},
};
var filterList = lstStudents.SelectMany(x => x.Credentials.Select(y =>
new Data
{
StudentName = x.Name,
CredentialKey = y.Key,
UserName = utilities.DecryptStringFromBase64String(y.Cred, key).Before(":::") ,
Password = utilities.DecryptStringFromBase64String(y.Cred, key).After(":::")
}))
.Where(d => d.CredentialKey == "N1")
.ToList();
Supporting classes,
public class Data
{
public string StudentName { get; set; }
public string CredentialKey { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
public class Student
{
public string Name { get; set; }
public List<Credential> Credentials { get; set; }
}
public class Credential
{
public string Key { get; set; }
public string Cred { get; set; }
}
In above code I am calling method DecryptStringFromBase64String 2 times, I would like to call it only one time and prepare my data class, how to do this? Thanks!
This will be easier if you tweak the query to use the actual LINQ language syntax (rather than the extension methods), as then you can use let:
var filterList = (
from x in lstStudents
from y in x.Credentials
let s = utilities.DecryptStringFromBase64String(y.Cred, key)
let d = new Data
{
StudentName = x.Name,
CredentialKey = y.Key,
UserName = s.Before(":::"),
Password = s.After(":::")
}
where d.CredentialKey == "N1"
select d
).ToList();
or to do the where sooner, to avoid some calculations / allocations:
var filterList = (
from x in lstStudents
from y in x.Credentials
where y.Key == "N1"
let s = utilities.DecryptStringFromBase64String(y.Cred, key)
let d = new Data
{
StudentName = x.Name,
CredentialKey = y.Key,
UserName = s.Before(":::"),
Password = s.After(":::")
}
select d
).ToList();
Personally I'd also change all the x, y, s, d to be more meaningful, but I've left them the same for now, so you can see how it maps.
An alternative would be, as noted by #Sinatr in the comments, to use a lambda with body:
var filterList = lstStudents.SelectMany(x => x.Credentials.Select(y => {
var s = utilities.DecryptStringFromBase64String(y.Cred, key);
return new Data {
StudentName = x.Name,
CredentialKey = y.Key,
UserName = s.Before(":::") ,
Password = s.After(":::")
};
}))
.Where(d => d.CredentialKey == "N1")
.ToList();

Linq query to join 2 lists of objects and get the altered values as list

I have 2 lists with below structure.
public class Team
{
public string Id { get; set; }
public Driver Driver { get; set; }
public Driver Codriver { get; set; }
}
public class Driver
{
public string DriverId { get; set; }
}
var modifiedTeams = new List<Team>
{
new Team {Id = "T1", Driver = new Driver { DriverId = "C2" }, Codriver = new Driver { DriverId = "D2"} },
new Team {Id = "T2", Driver = new Driver { DriverId = "D1"} }
};
var originalTeams = new List<Team>
{
new Team {Id = "T1", Driver = new Driver { DriverId = "D1" }, Codriver = new Driver { DriverId = "C1"} },
new Team {Id = "T2", Driver = new Driver { DriverId = "D2"}, Codriver = new Driver { DriverId = "C2"} }
};
I want to get a list of all moved team ids along with the member moved. Eg: Team T1 Driver is replaced by Team T2 Codriver. So I want a list as [{T1,Driver},{T2,Codriver}]
Final Output for above movedTeams is:
[{T1,"Driver"},{T2, "Codriver"},{T1, "Driver"}]
Can someone please help me with this.
This will get you want you want, I altered the driver class a bit making LINQ easier. I'm sure it could be done with less lines but would probably be harder to read. I kept your output format [{T1,"Driver"},{T2, "Codriver"},{T1, "Driver"}], but you should reconsider that and group them together better.
public class Team
{
public string Id { get; set; }
public List<Driver> Drivers { get; set; }
}
public class Driver
{
public string DriverId { get; set; }
public bool IsMainDriver { get; set; }
}
public List<string[]> GetDriverMovementList(List<Team> originalTeams, List<Team> modifiedTeams)
{
var output = new List<string[]>();
foreach (var team in modifiedTeams)
{
foreach (var driver in team.Drivers)
{
// check this team
var driverOrig = originalTeams.Where(x => x.Id == team.Id).SelectMany(x => x.Drivers).Where(x => x.IsMainDriver != driver.IsMainDriver).FirstOrDefault();
if (driverOrig == null)
{
// check other teams
driverOrig = originalTeams.Where(x => x.Id != team.Id).SelectMany(x => x.Drivers).Where(y => y.DriverId == driver.DriverId).FirstOrDefault();
}
if (driverOrig != null)
{
var oldTeam = originalTeams.Where(x => x.Drivers.Contains(driverOrig)).FirstOrDefault();
output.Add(new string[] { team.Id, GetDriverRoleName(driver.IsMainDriver) });
output.Add(new string[] { oldTeam.Id, GetDriverRoleName(driverOrig.IsMainDriver) });
}
}
}
return output;
}
public static string GetDriverRoleName(bool isMainDriver)
{
if (isMainDriver) { return "Driver"; } else { return "Codriver"; }
}

Linq query. List of 4 items becomes only 1 items in list

I am working with asp.net mvc and I am calling a rest service and receiving 4 receipts i a list (Se picture below).
The problem is that I want to convert the list of result that I have to a response result but still have the 4 items the the list.
When returning the response to my view instead of having 4 items in the list I only have 1 Store, 1 Receipt in the list.
What is wrong with my Linq query? I have addedd .ToList() almost everywhere.
Thanks in advance.
The asp.net
I have a model with a class as below
public class ReceiptsViewModel
{
public List<RestAPI.Store> Stores { get; set; }
public List<RestAPI.POSProvider> Providers { get; set; }
public List<RestAPI.Receipt> Receipts { get; set; }
public List<RestAPI.StoreChain> StoreChains { get; set; }
}
[HttpGet]
public ActionResult Receipts()
{
Guid userId = Guid.Parse(CookieHelper.GetCookieValue("UserId"));
var result = ReceiptService.GetReceiptsByUserId(userId);
var response = (from r in result.Receipts
select new Eflag.Receipt.Web.Mvc.Areas.Dashboard.Models.User.ReceiptsViewModel()
{
Receipts = new List<Models.RestAPI.Receipt>()
{
new Models.RestAPI.Receipt()
{
ReceiptUniqueId = r.ReceiptUniqueId,
ReceiptId = r.ReceiptId,
CashierId = r.CashierId,
CashierName = r.CashierName,
ReceiptDateTime = r.ReceiptDateTime,
POSPlace = r.POSPlace,
Total = r.Total,
TotalTax = r.TotalTax,
TotalNet = r.TotalNet,
TotalDiscount = r.TotalDiscount,
Rounding = r.Rounding,
ItemAmount = r.ItemAmount,
Currency = r.Currency,
CurrencyCode = r.CurrencyCode,
MembershipCardUsed = r.MembershipCardUsed,
MembershipCardId = r.MembershipCardId,
Revoked = r.Revoked,
CardCompany = r.CardCompany,
FreeText = r.FreeText,
Items = (from i in r.Items
select new Item()
{
ItemUniqueId = i.ItemUniqueId,
ItemId = i.ItemId,
Ean = i.Ean,
Name = i.Name,
CurrentPrice = i.CurrentPrice,
RegularPrice = i.RegularPrice,
Color = i.Color,
ItemRowCount = i.ItemRowCount,
ItemOrder = i.ItemOrder,
TotalGrossAmount = i.TotalGrossAmount,
TotalNetAmount = i.TotalNetAmount,
Removed = i.Removed
}).ToList()
}
}.ToList(),
Stores = new List<Store>()
{
new Store()
{
StoreUniqueId = r.Store.StoreUniqueId,
StoreId = r.Store.StoreId,
Name = r.Store.Name,
CorporateId = r.Store.CorporateId,
Adress = r.Store.Adress,
PostalCode = r.Store.PostalCode,
Phone = r.Store.Phone,
Email = r.Store.Email,
Status = r.Store.Status
}
}.ToList(),
Providers = new List<POSProvider>()
{
new POSProvider()
{
POSProviderUniqueId = r.POSProvider.POSProviderUniqueId,
Name = r.POSProvider.Name,
CorporateId = r.POSProvider.CorporateId,
Adress = r.POSProvider.Adress,
PostalCode = r.POSProvider.PostalCode,
Phone = r.POSProvider.Phone,
ContactPerson = r.POSProvider.ContactPerson,
Email = r.POSProvider.Email,
Status = r.POSProvider.Status
}
}.ToList(),
StoreChains = new List<StoreChain>()
{
new StoreChain()
{
StoreChainUniqueId = r.StoreChain.StoreChainUniqueId,
Name = r.StoreChain.Name,
StoreChainId = r.StoreChain.StoreChainId,
Status = r.StoreChain.Status
}
}.ToList()
});
return View(response);
}
The problem is that you are creating a list of ReceiptsViewModel instead of a single one with multiple receipts contained inside.
Change the code to something like this:
var response = new Eflag.Receipt.Web.Mvc.Areas.Dashboard.Models.User.ReceiptsViewModel
{
Receipts = result.Receipts,
Stores = result.Receipts.Stores,
//rest of code snipped
}
Try using ConvertAll methon of List collection. Docs here.
Example:
var response = result.Receipts.ToList().ConvertAll(x=> new Eflag.Receipt.Web.Mvc.Areas.Dashboard.Models.User.ReceiptsViewModel() {
//do your convertations here
});

Collection not populated with Fluent NHibernate

I am having an odd error when using Fluent NHibernate. I have an entity object called Module that is my "aggregate root" if you will. I created and tested my mappings for the Module class and the various related classes and tried creating a Module with all of its fields filled out and saving it. This worked correctly.
My problem is when I try to retrieve the objects from the database. The Module object comes back just fine, however any of the collections it contains are all empty even though I see the objects in the database tables!! I could really use a hand on this one, I hope somone can help!
edit: added the code for BuildDeriveModule below.
Here is my test:
var dei1 = BuildDeriveModule();
var sessionSource = Injector.Resolve<ISessionSource>();
using (var session = sessionSource.CreateSession())
{
using (var transaction = session.BeginTransaction())
{
session.Save(dei1);
transaction.Commit();
}
}
Module item = null;
using (var session = sessionSource.CreateSession())
{
item = session
.CreateCriteria(typeof(Module))
.Add(Restrictions.Eq("ModuleId", dei1.ModuleId))
.UniqueResult<Module>();
Assert.Equal<Module>(dei1, item);
Assert.Equal<int>(4, item.Variables.Count);
}
My Module class looks like this: (Note: Entity comes from FluentNHibernate.Data.Entity)
public class Module : Entity, IEntity
{
public Module()
{
Variables = new HashedSet<ModuleVariable>();
}
public virtual string ModuleId
{
get;
set;
}
public virtual ISet<ModuleVariable> Variables
{
get;
set;
}
public virtual Variable StratumVariable
{
get;
set;
}
public virtual Stratum DefaultStratum
{
get;
set;
}
public virtual ISet<Stratum> OptionalStrata
{
get;
set;
}
public virtual DateTime LastUpdated
{
get;
set;
}
#region Override Methods
public override string ToString()
{
return this.ModuleId;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var other = obj as Module;
if (other == null) return false;
if (other.ModuleId != this.ModuleId) return false;
return true;
}
public override int GetHashCode()
{
return ModuleId.GetHashCode();
}
#endregion
}
And my Mapping looks like this:
public class ModuleMap : ClassMap<Module>
{
public ModuleMap()
{
Id(x => x.Id);
Version(x => x.LastUpdated);
Map(x => x.ModuleId)
.Unique()
.Not.Nullable();
HasMany<ModuleVariable>(x => x.Variables)
.Inverse()
.Cascade.SaveUpdate();
References<Variable>(x => x.StratumVariable)
.Not.Nullable()
.Cascade.SaveUpdate();
References<Stratum>(x => x.DefaultStratum)
.Not.Nullable()
.Cascade.SaveUpdate();
HasMany<Stratum>(x => x.OptionalStrata)
.Inverse()
.Cascade.SaveUpdate();
}
}
BuildDeriveModule's code:
private Module BuildDeriveModule()
{
var pp01 = new Relation
{
RelationId = "PP01"
};
var hh01 = new Relation
{
RelationId = "HH01"
};
var stdei1 = new Variable
{
VariableId = "STDEI1",
Relation = pp01
};
var frameId = new Variable
{
VariableId = "FRAME_ID",
Relation = pp01
};
var persno = new Variable
{
VariableId = "PERSNO",
Relation = pp01
};
var hp = new Driver
{
Name = "HP",
Phase = 1
};
hp.KeyVariables.Add(frameId);
hp.KeyVariables.Add(persno);
var r2p1 = new Variable
{
VariableId = "R2P1",
Relation = pp01
};
var age = new Variable
{
VariableId = "AGE",
Relation = pp01
};
var marst = new Variable
{
VariableId = "MARST",
Relation = pp01
};
var doctp = new Variable
{
VariableId = "DOCTP",
Relation = hh01
};
pp01.AddVariable(stdei1);
pp01.AddVariable(r2p1);
pp01.AddVariable(age);
pp01.AddVariable(marst);
hh01.AddVariable(doctp);
var defaultStratum = new Stratum
{
Number = -1,
Driver = hp
};
var dei1 = new Module
{
ModuleId = "DEI1",
StratumVariable = stdei1,
DefaultStratum = defaultStratum
};
var mv_r2p1 = new ModuleVariable
{
ModuleId = dei1,
VariableId = "R2P1",
UploadId = r2p1,
DownloadId = r2p1,
HasSubunits = true
};
var mv_age = new ModuleVariable
{
ModuleId = dei1,
VariableId = "AGE",
UploadId = age,
DownloadId = age,
HasSubunits = true
};
var mv_marst = new ModuleVariable
{
ModuleId = dei1,
VariableId = "MARST",
UploadId = marst,
DownloadId = marst,
HasSubunits = true
};
var mv_doctp = new ModuleVariable
{
ModuleId = dei1,
VariableId = "DOCTP",
UploadId = doctp,
DownloadId = doctp,
HasSubunits = false
};
dei1.AddVariable(mv_r2p1);
dei1.AddVariable(mv_age);
dei1.AddVariable(mv_marst);
dei1.AddVariable(mv_doctp);
return dei1;
}
OK, I think I got it to work. I removed the .Inverse() from thins line
HasMany<ModuleVariable>(x => x.Variables)
.Inverse()
.Cascade.SaveUpdate();
in ModuleMap and the unit test worked. I'm not quite sure why though, so if anyone can point out that out it would be appreciated.

Categories