Lambda expression - select single object with a IEnumerable<> property - c#

Is it possible to select a single object and populate a containing IEnumerable property with a single Lambda expression?
Something like this:
var someViewModel = _repository.Table.Where(x => x.Id == someId)
.Select(new ListViewModel(){
GroupId = x.Group.Id,
GroupTitle = x.Group.Title
List = ?? // Select new SubViewModel and add it to IEnumerable<SubViewModel>
})
The result I'm after is a new object (ListViewModel in this case) that contains 3 properties. "List" being a collection of newly selected objects.
Is this possible? Am I coming at this from the wrong angle?
Thanks!
Update:
Let me try again :) Keep in mind that my naming is fictional here. Given the following two classes I would like to construct a DB query using a Lambda expression which creates a single "ListViewModel" that contains a collection of "SubViewModel". Does this help clarify?
public class SubViewModel
{
public int Id { get; set; }
public string Title { get; set; }
}
public class ListViewModel
{
public int GroupId { get; set; }
public string GroupTitle { get; set; }
public IEnumerable<SubViewModel> List { get; set; }
}

I'm not sure if I understand your question correctly but here is what I am thinking, you need to create a new IEnumberable and add the item to that collection.
var someViewModel = _repository.Table.Where(x => x.Id == someId)
.Select(new ListViewModel()
{
GroupId = x.Group.Id,
GroupTitle = x.Group.Title
List = new List<SubViewModel> { new SubViewModel(x) }
});

Related

C# Automapper how to create a list with nested mapping?

I am trying to map into the list, which supposes to have two other lists inside. Is it doable? I looked at the documentation but couldn't find what I needed unless I misunderstood something.
CompanyActivityReport.cs
public int OrganisationID { get; set; }
public string OrganisationName { get; set; }
public Nullable<int> OrganisationSubTypeID { get; set; }
public CompanyActivityReportTask ReportTask{get; set;}
public CompanyActivityReportNote ReportNotes{get; set;}
My mapping:
var config = new MapperConfiguration(c =>
{
c.CreateMap<OrganisationMain,CompanyActivityReport>();
c.CreateMap<TaskMain, CompanyActivityReportTask>();
c.CreateMap<NoteMain, CompanyActivityReportNote>();
});
var mapper = new Mapper(config);
List<CompanyActivityReport> TestList = mapper.Map<List<CompanyActivityReport>>(OrganisationMainsList).ToList();
Guess you problably need to map each item individually like:
List<CompanyActivityReport> TestList = OrganisationMainsList.Select(x => mapper.Map<CompanyActivityReport>(x))
Edit: Select return a Enumerable so if you wish to mantain the behaviour a .ToList() is required:
List<CompanyActivityReport> TestList = OrganisationMainsList.Select(x => mapper.Map<CompanyActivityReport>(x)).ToList()

How to update a property of an complexObj. inside a Document inside a List<complexObj>? MongoDB C# net.Driver

how to update one property of a document in MongoDb with C# net.Driver.
My data model in C# looks like this:
public class MyMediListsWrapper
{
[BsonId]
public Guid Id { get; set; }
public DateTime Datum { get; set; }
public bool IsActiv { get; set; }
public List<Medi> MediLsts { get; set; }
}
public class Medi
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Typ { get; set; }
public string Vmax { get; set; }
}
Now I want to update only one property of one Obj. (Vmax='Test') of the nested List MediLsts.
I wand to filter the collection MyMediListsWrapper by SingleOrDefault IsActiv=true and then I want to filter 'in this Document' the Medi-Obj. from the nested List inside by Guid='XcPwoEaB8Ey7XR1AEB+fLQ=='
and then update Vmax='Test'.
I have a little bit of code, but it doesn't achieve what I want. I have trouble to do the filter first for IsActiv and then filter inside of that Document again for a different property. And I don't know how to write the code for the update later (if found). Thx for help.
My Code:
var db = client.GetDatabase(MySecret.MyMongoDbName);
var myMediListsWrapper = db.GetCollection<MyMediListsWrapper>(MySecret.MyWrapperColName);
var filter = Builders<MyMediListsWrapper>.Filter;
var filterColAndFilterLstObj = filter.And(
filter.Eq(x => x.IsActiv, true),
filter.ElemMatch(x => x.MediLsts, lst => lst.Id == mySearchGuid));
//Just a Test -- I want to UPDATE a property NOT find a entry
//and this is WRONG because it give me a obj of the outer class not the Medi-Obj.
var result = await myMediListsWrapper.Find(filterColAndFilterLstObj).SingleOrDefaultAsync(); ```
the following update command should do the trick:
await collection.UpdateOneAsync(
filter: w => w.IsActiv && w.MediLsts.Any(m => m.Id == mySearchGuid),
update: Builders<MyMediListsWrapper>.Update.Set(m => m.MediLsts[-1].Vmax, "TEST"));
the thing to note here is the [-1] array/list index above.
the driver translates that to the following $set operation:
$set: { "MediLsts.$.Vmax" : "TEST" }
-1 index position is something special the mongo driver uses to denominate $ which is the first positional operator.
i.e. update the first array element that qualifies for the $elemMatch condition of the filter.
.MediLsts.Any(...) is the LINQ equivalent of filter.ElemMatch(...)

cannot implicity convert type System.Collections.GenericList<AnonymousType#1>

Please have patience with me I'm new to linq and have a question about a couple of errors that I am not understanding any help would be greatly appreciated.
the error I am receiving in the title of my question.
my childproduct variable returns every single character indiviuallly I would like them to be a string version of the productId and Childtext parameters.
Code:
public class AOAPlusChildModel
{
public List<string> LongName { get; set; }
public List<string> Text { get; set; }
public List<string> ProductId { get; set; }
public static List<AOAPlusChildModel> GetChildProducts()
{
List<AOAPlusChildModel> cp = new List<AOAPlusChildModel>();
List<AoaUserDefinedVWGetAOAPlusProducts> ChildProductsLists = AoaSvcClient.Client.Context.AoaUserDefinedVWGetAOAPlusProductss.Where(a => a.MasterProductFlag == false && a.Affiliate == "VA").ToList();
var childProducts = ChildProductsLists.SelectMany(p => p.LongName, (id, childtext) =>
new { ProductId = id.ProductId, Text = childtext }).ToList();
cp = childProducts.ToList();
return cp;
}
}
Your variable cp is a List<AOAPlusChildModel> but the linq query is projecting an anonymous type. Instead of creating a new anonymous type create a new AOAPlusChildModel
return ChildProductsLists.SelectMany(p => p.LongName,
(id, childtext) =>
new AOAPlusChildModel {
ProductId = id.ProductId,
Text = childtext }).ToList();
Reason for following errors are that you perform ChildProductsLists.SelectMany(p => p.LongName) which basically now returns a collection of strings - this collection of strings you are trying to assign as a new AOAPlusChildModel object which does not hold string properties but List<string> properties.
I think your model should look like:
public string LongName { get; set; }
public string Text { get; set; }
public string ProductId { get; set; }

Making sure a value is equal to one of many in LINQ

I have an IEnumerable containing values like "ABC", "DEF", etc.
I'm trying to form a LINQ query where the value of a property in my object may be equal to one of the many values contained in my IEnumerable. How do I form that LINQ query?
var statesFilter = new List<string>();
statesFilter.Add("NY");
statesFilter.Add("CA");
var employees = new List<Employee>();
employees = getDataFromSomewhere();
// Code below is not working. Just wanted to give you an idea about my LINQ query
var myFilteredList = employees.Where(x => x.State.Contains(statesFilter));
Employee class could be something like this:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string State { get; set; }
}
If State property is of type string, you should change your Where to the following:
var myFilteredList = employees.Where(x => statesFilter.Contains(x.State));
Also, you can do this:
var myFilteredList = employees.Where(x => statesFilter.Any(s=>s==x.State));
Condition should be
x=>statesFilter.Contains(x.State))

RavenDB cross entity query matching on non-identifier property

I have the following entity collections in RavenDB:
public class EntityA
{
public string Id { get; set; }
public string Name { get; set; }
public string[] Tags { get; set; }
}
public class EntityB
{
public string Id { get; set; }
public string Name { get; set; }
public string[] Tags { get; set; }
}
The only thing shared is the Tags collection: a tag of EntityA may exist in EntityB, so that they may intersect.
How can I retrieve every EntityA that has intersecting tags with EntityB where the Name property of EntityB is equal to a given value?
Well, this is a difficult one. To do it right, you would need two levels of reducing - one by the tag which would expand out your results, and another by the id to collapse it back. Raven doesn't have an easy way to do this.
You can fake it out though using a Transform. The only problem is that you will have skipped items in your result set, so make sure you know how to deal with those.
public class TestIndex : AbstractMultiMapIndexCreationTask<TestIndex.Result>
{
public class Result
{
public string[] Ids { get; set; }
public string Name { get; set; }
public string Tag { get; set; }
}
public TestIndex()
{
AddMap<EntityA>(entities => from a in entities
from tag in a.Tags.DefaultIfEmpty("_")
select new
{
Ids = new[] { a.Id },
Name = (string) null,
Tag = tag
});
AddMap<EntityB>(entities => from b in entities
from tag in b.Tags
select new
{
Ids = new string[0],
b.Name,
Tag = tag
});
Reduce = results => from result in results
group result by result.Tag
into g
select new
{
Ids = g.SelectMany(x => x.Ids),
g.First(x => x.Name != null).Name,
Tag = g.Key
};
TransformResults = (database, results) =>
results.SelectMany(x => x.Ids)
.Distinct()
.Select(x => database.Load<EntityA>(x));
}
}
See also the full unit test here.
There is another approach, but I haven't tested it yet. That would be to use the Indexed Properties Bundle to do the first pass, and then map those results for the second pass. I am experimenting with this in general, and if it works, I will update this answer with the results.

Categories