assign value to a new list using linq - c#

Let's say I have a class called Company
public class Company
{
public string name;
public string id;
}
I have a list called CompanyList
var companyList = new List<Company>();
I would like to assign name = "Company A", id = "001" to this empty companyList variable.
How do I do so?
companyList.FirstOrDefault().Name = "Company A";
companyList.FirstOrDefault().Id = "001";

Before you can assign a value to a company in a collection, you must add a company to the collection. You are setting the values of that company, not of the collection itself.
Use either:
var companyList = new List<Company>();
companyList.Add(new Company { Name = "Company A", Id = "001" });
Or:
var companyList = new List<Company>();
companyList.Add(new Company());
// Assumes you want to modify the first company in the list
companyList[0].Name = "Company A";
companyList[0].Id = "001";

You could use collection initializer:
var companyList = new List<Company>{ new Company { Name = "Company A", Id = "001" } };
effectively the same as bellow, a bit more compact
var companyList = new List<Company>();
companyList.Add(new Company { Name = "Company A", Id = "001" });

It seems like you simply need to create an instance of Company and then add it to your list. Here is an example:
List<Company> companyList = new List<Company>();
Company currentCompany = new Company(){id="001", Name="Company A"};
companyList.Add(currentCompany);
Side note ** Be aware of using the code snippet denoted in your question
companyList.FirstOrDefault().Name = "Company A";
companyList.FirstOrDefault().Id = "001";
This could lead to uncaught null reference exceptions, crashing your program. Always check for null when using FirstOrDefault() to instantiate an object.
Company temp = companyList.FirstOrDefault();
if(temp !=null)
{
temp.Name = "Company A";
temp.id = "001";
}

Here is an example where you can initialize the collection directly:
var companyList = new List<Company> {
new Company { name = "Company A", id = "001" },
new Company { name = "Company B", id = "002" }
};

To update the list safetly ( without execption ) you shoud do somthing like this :
var company = companyList.FirstOrDefault() ;
if (company != null) {
company.Name ="aaa";
company.Id = "123" ;
}

Related

How to convert dynamic to unknown class in runtime

I have a dynamic rule engine and i want to pass class to this and each time the class is sent differently.
For example:
Order MyOrder = new Order()
{
OrderId = 1,
Customer = new Customer()
{
FirstName = "John",
LastName = "Doe",
Country = new Country()
{
CountryCode = "AUS"
}
},
Items = new List<Item>(){
new Item(){ ItemCode = "MM23", Cost=5.25M},
new Item(){ ItemCode = "LD45", Cost=5.25M},
new Item(){ ItemCode = "Test", Cost=3.33M},
}
};
I want to change this:
var compiledRule = engine.CompileRule<Order>(rule);
to :
dynamic obj = MyOrder;
var compiledRule = engine.CompileRule<?????>(rule);
how can I get Type of obj and put instead of "????"
I found solution after search a lot
var engine = new MRE();
var compiledRule = engine.CompileRule<Order>(rule);
change to:
var engine = new MRE();
var compiledRule = typeof(MRE).GetMethod("CompileRule").MakeGenericMethod(myOrder.GetType())
.Invoke(engine, new object[] { rule}) as dynamic;

LINQ to handle IEnumerable and remove unmatch items from sub entity

I encountered a problem in my work recently, the following is the source code,
this.NameList = new ObservableCollection<Name>();
List<Others> others1 = new List<Others>();
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
List<Others> others2 = new List<Others>();
others2.Add(new Others() { Company = "Company2", School = "School2" });
others2.Add(new Others() { Company = "Company2", School = "School2" });
others2.Add(new Others() { Company = "Company2", School = "School2" });
List<Others> others3 = new List<Others>();
others3.Add(new Others() { Company = "Company3", School = "School3" });
others3.Add(new Others() { Company = "Company3", School = "School3" });
others3.Add(new Others() { Company = "Company3", School = "School3" });
this.NameList.Add(new Name() { FirstName = "Jacob", LastName = "Deng", Others = others1 });
this.NameList.Add(new Name() { FirstName = "David", LastName = "Xu", Others = others2 });
this.NameList.Add(new Name() { FirstName = "Helen", LastName = "Liu", Others = others3 });
please click here to see the output of above code
And then please read the following code,
List<Others> others1 = new List<Others>();
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
List<Others> others2 = new List<Others>();
List<Others> others3 = new List<Others>();
this.NameList.Add(new Name() { FirstName = "Jacob", LastName = "Deng", Others = others1 });
this.NameList.Add(new Name() { FirstName = "David", LastName = "Xu", Others = others2 });
this.NameList.Add(new Name() { FirstName = "Helen", LastName = "Liu", Others = others3 });
Please click here for the output of the second snippet code
From above two snippets, you might notice that the second snippet doesn't contain any items in other2 and other3, you can easily understand from the preview output.
Now the question comes, how do we use LINQ to IEnumerable to handle such case, how to use LINQ to remove those items from Others entity? but we need to keep other2 and other3 not to be null (keep it count is 0). Besides LINQ, are there any other solutions?
I tried to use the following, but failed,
var others = ((MyVM)DataContext).NameList.Select(n => n.Others.Where(o => o.School == "School1")).ToList();
I just did some test, if we don't use LINQ, then we can use the following snippet code to fix my it.
ObservableCollection<Name> nameList = ((MyVM)DataContext).NameList;
foreach(Name n in nameList)
{
List<Others> removeList = new List<Others>();
for(int i=0;i<n.Others.Count;i++)
{
if(n.Others[i].School!="School1")
{
removeList.Add(n.Others[i]);
}
}
foreach(Others other in removeList)
{
n.Others.Remove(other);
}
}
But it looks very redundant, and we know that LINQ is very useful and i believed that it can be fixed with LINQ. Hope someone could help me to fix it with LINQ,thanks.
Appreciate if someone could help me. Thanks a lot.
It's better to use List<T>.RemoveAll in your case. See Using LINQ to remove elements from a List<T> for more details.
ObservableCollection<Name> nameList = ((MyVM)DataContext).NameList;
foreach(Name n in nameList)
{
n.Others.RemoveAll(s => s.School != "School1");
}
Linq is good at read-only iterating instead of updating/deleting. If you insist using Linq, you have to re-construct each item.
var newList = from nl in this.namelist
// this list can be empty but never null
let notSchool1 = (from s in nl.Others
where s.School != "School1"
select s).ToList()
select new Name
{
FirstName = nl.FirstName,
LastName = nl.LastName,
Others = noSchool1
};
this.NameList = new ObservableCollection<Name>(newList);
Above code may break other functionalities in your application, because these items are observed.
As I understand your question,
You want to remove others whose school value is not 'School1'. There are different way available for that but I recommend to filter the data from NameList which you want.
You can try below code to get others list with 'School1'
var result = NameList.Select(name => new Name()
{
FirstName = name.FirstName,
LastName = name.LastName,
Others = name.Others.Where(obj => obj.School == "School1").ToList()
}
).ToList();

Check if a string contains a value within a generic list and replace it

I have a string with a message containing some fields I want to swap out to actual values
var message = "Hi [CustomerName]. Its [TODAY], nice to see you were born on the [DOB]!";
var mappingCodes = new List<string> {"[CUSTOMER_NAME]","[DOB]",[TODAY]};
var customEmails = new Dictionary<string, string>();
var today = DateTime.Now;
var customers = new List<Customer>()
{
new Customer()
{
FirstName = "Jo",
LastName = "Bloggs",
Email = "jo#bloggs.com",
DOB = "10/12/1960"
}
};
foreach (var customer in customers)
{
var emailMessage = "";
customEmails.Add(customer.Email,emailMessage);
}
What I'm trying to do is loop through each of the customers and take the message replacing any of the mappingCodes with actual codes.
e.g. [Today] Would be the today and CustomerName would be Customer.FirstName + Customer.LastName
There could be 1000's of customers so I need something robust. I'm just not sure how to first check the string contains any of the mappingCodes and then replace them with the desired values.
Any advice?
You could try something like this. String.Format is rather efficient. It also would allow you to format Date.Today, if you want.
var customers = new List<Customer>()
{
new Customer()
{
FirstName = "Jo",
LastName = "Bloggs",
Email = "jo#bloggs.com",
DOB = "10/12/1960"
}
};
foreach (var customer in customers)
{
var emailMessage = String.Format("Hi {0}. Its {1}, nice to see you were born on the {2}!", customer.FirstName, DateTime.Today, customer.DOB);
customEmails.Add(customer.Email,emailMessage);
}
You can use Regex.Replace(string, MatchEvaluator):
var customers = new[] {
new {
Name = "Fred Flintstone",
City = "Bedrock"
},
new {
Name = "George Jetson",
City = "Orbit City"
}
};
string template = "Hello, [NAME] from [CITY]!";
var re = new Regex(#"\[\w+\]"); // look for all "words" in square brackets
foreach (var customer in customers)
{
Trace.WriteLine(
re.Replace(template, m => {
// determine the replacement string
switch (m.Value) // m.Value is the substring that matches the RE.
{
// Handle getting and formatting the properties here
case "[NAME]":
return customer.Name;
case "[CITY]":
return customer.City;
default:
// The "mapping code" is not supported, I just return the
// original substring
return m.Value;
}
}));
}
Obviously the above is just the general approach, you'll have to modify it to support your mapping codes and data structures.

How can i use DefaultIfEmpty when mocking a database context?

I wrote the following linq query that creates a new object by joining data together as you can see:
var translations = from t in context.Translations
join token in context.Tokens on t.Guid equals token.Guid
join t2 in context.Translations on new { t.Guid, LanguageCode = "fr" } equals new { t2.Guid, t2.LanguageCode} into j //TODO: fr needs to be replaced by the language of the translators account
from j2 in j.DefaultIfEmpty()
where t.LanguageCode == String.Empty
orderby t.Text
select new TranslationView
{
Guid = t.Guid,
LanguageCode = j2.LanguageCode,
SourceText = t.Text,
Translation = j2.Text,
IsNew = j2.Text == null,
Notes = token.Notes,
Required = token.Required,
Type = (Token.TokenType)token.Type,
Location = (Token.LocationType)token.Location
};
The problem is that I am now trying to write a unit test with Rhino.Mocks and it returns the error Object reference not set to an instance of an object.
So my question now is, is there a better way that this query could be written? A way in which it will work in both a real situation and the Unit test situation?
I tried passing a value in in the DefaultIfEmpty() bit and it made it work for the Mock, but then the main code failed.
EDIT
Unit test code:
[Test]
public void Build_Translation_List_TwoItems_Context()
{
//Arrange: Setup context
var context = setupContext();
//Act: Pass the context through
var result = TranslationHelpers.BuildTranslationList(context, 1);
//Result
result.TranslationList.Count.ShouldEqual(2);
result.PagingInfo.TotalItems.ShouldEqual(2);
}
SetupContext Method:
public static ITranslationContext setupContext()
{
var context = new Mock<ITranslationContext>();
context.SetupProperty(x => x.Tokens, new UnitTestHelpers.FakeDbSet<Token>
{
new Token
{
DateAdded = DateTime.Now,
Guid = Guid.Parse("f3099a43-e12d-4ea3-ba06-265fde807f03"),
LastUpdated = DateTime.Now,
Location = (short)0,
Type = (short)0,
LocationDescription = "Test 1",
Notes = "Testing 1",
Required = "Testing"
},
new Token
{
DateAdded = DateTime.Now,
Guid = Guid.Parse("7D6937D8-F7E1-4B92-934E-465683874B65"),
LastUpdated = DateTime.Now,
Location = (short)0,
Type = (short)0,
LocationDescription = "Test 3",
Notes = "Testing 3",
Required = "Testing"
},
});
context.SetupProperty(x => x.Translations, new UnitTestHelpers.FakeDbSet<Translation>
{
new Translation{Guid = Guid.Parse("f3099a43-e12d-4ea3-ba06-265fde807f03"), LanguageCode = String.Empty, Text = "Testing 1"},
new Translation{Guid = Guid.Parse("f3099a43-e12d-4ea3-ba06-265fde807f03"), LanguageCode = "fr", Text = ""},
new Translation{Guid = Guid.Parse("7D6937D8-F7E1-4B92-934E-465683874B65"), LanguageCode = String.Empty, Text = "Testing 3"},
new Translation{Guid = Guid.Parse("7D6937D8-F7E1-4B92-934E-465683874B67"), LanguageCode = "fr", Text = "Testing 4"}
});
return context.Object;
}
Any help would be much appreciated.
DefaultIfEmpty() will not create a "default" j2. It will just get data even if j2 is null.
It's just like an SQL LEFT JOIN
So you have to test for nullity to avoid NRE.
instead of
LanguageCode = j2.LanguageCode
try to do
LanguageCode =j2 != null ? j2.LanguageCode : string.Empty // or null
Pass mocked context to your method, and LINQ will do it's job. Then verify returned list of TranslationView objects.
Here is how your test should look like:
List<Translations> translations = // create translations
List<Tokens> tokens = // create tokens
var context = MockRepository.GenerateStub<IMyContext>();
context.Stub(c => c.Translations).Return(translations);
context.Stub(c => c.Tokens).Return(tokens);
var foo = new Foo(context);
var views = foo.GetTranslationView();
// verify returned views

Anonymous Type in LINQ

I'm trying to get anonymous object from query:
var myList = from td in MyObjectList
select new
{
a = td.a,
b = td.b,
c = td.c,
name = (from r in contex.NewList
where r.aa == td.a && r.bb == td.b
select r.Name).ToList()
};
I would like name to have r.Name value cause I expect that name list contains only one element. If it contains 0 elements I would like name to have value NONE if more then 1 element then exception should be thrown or something.
Is it even possible to achieve something like that? Thanks for help.
Instead of .ToList() use
.SingleOrDefault() ?? (td.a == 0 ? "XNone" : "None")
Edit: Changed anwer based on comment.
Also I would recomend not to put such logic into Linq-to-SQL. Sometimes this can result in big chunk of highly-unoptimized SQL code and, unless you dont mind some performance isues, can result in much slower SQL execution.
You can achieve that using SingleOrDefault and a temporary variable within the expression. Something like this:
var myList =
from td in MyObjectList
let nameValue = contex.NewList
.Where(r => r.aa== td.a && r.bb == td.b)
.Select(r => r.Name)
.SingleOrDefault()
select new
{
a = td.a,
b = td.b,
c = td.c,
name = nameValue ?? "NONE"
};
Update: instead of presenting almost the same solution as #Euphorics answer, I've restructured the code a bit. I often find nested LINQ expressions making things less readable. Converting comprehension syntax into call chains could improve that.
Update 2: with some added requirements, the following select should do the trick:
select new
{
a = td.a,
b = td.b,
c = td.c,
name = nameValue ?? (td.a == 0 ? "XNone" : "None")
};
Theoretically you CAN'T.
Unless you have a type from where you could inspect lambda properties.
The trick is to convert your anonymous object to json and deserialize it into a known type that you must have in advance.
Caution working with EF core because your linq query will be executed CLIENT side!!.
That means that all the records will be retrieved from your dbset and evaluate on client.
Do NOT use code like this on EF dbset iquerables.
Any away I will copy some extensions methods code to do it so.
Having a defined type like...
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
Extension convert any object to json string...
public static class ObjectExtensions
{
public static string ToJson(this object source)
{
return JsonConvert.SerializeObject(source, Formatting.None);
}
}
Extension convert any json string to typed object...
public static class StringExtensions
{
public static T FromJson<T>(this string source) where T : class
{
return JsonConvert.DeserializeObject<T>(source);
}
}
Some xUnit Test
[Fact]
public void AddSelectTest()
{
var data = new[]
{
new {Id = 01, Name = "Engineering", GroupName = "Engineering and Development"},
new {Id = 02, Name = "Tool Design", GroupName = "Tool Design and Research"},
new {Id = 03, Name = "Sales", GroupName = "Sales and Marketing"},
new {Id = 04, Name = "Marketing", GroupName = "Marketing and Sales"},
new {Id = 05, Name = "Purchasing", GroupName = "Inventory Management"},
new {Id = 06, Name = "Research and Development", GroupName = "Development and Research"},
new {Id = 07, Name = "Production", GroupName = "Manufacturing and Production"},
new {Id = 08, Name = "Production Control", GroupName = "Control and Production"},
new {Id = 09, Name = "Human Resources", GroupName = "Human Resources and Administration"},
new {Id = 10, Name = "Finance", GroupName = "Finance and Executive General"},
new {Id = 11, Name = "Information Services", GroupName = "Information Services and Administration"},
new {Id = 12, Name = "Document Control", GroupName = "Document Control and Quality Assurance"},
new {Id = 13, Name = "Quality Assurance", GroupName = "Administration and Quality Assurance"},
new {Id = 14, Name = "Facilities and Maintenance", GroupName = "Maintenance and Facilities"},
new {Id = 15, Name = "Shipping and Receiving", GroupName = "Receiving and Shipping"},
new {Id = 16, Name = "Executive", GroupName = "Executive General and Administration"}
};
var queryable = data.AsQueryable();
var first = queryable.Select(d => new { Id = d.Id, Name = d.Name }).FirstOrDefault(d => d.ToJson().FromJson<Department>().Id == 1);
Assert.True(first != null, "Expected a department value but 'null' was found.");
}
Once again... let me say that if you are querying anonymous in memory object it could be ok, but be very cautious if your iquerable cames from EF core, since client side evaluation will happen.
Please enable throw exception warning when client side evaluation happens on your EF core code thought your DbContextOptionsBuilder, to prevent EF Core of executing client side evaluation code. You could do it follows..
builder.UseSqlServer(connection, sql =>
{
sql.EnableRetryOnFailure();
sql.MigrationsAssembly(assembly);
})
.UseQueryTrackingBehavior(track ? QueryTrackingBehavior.TrackAll : QueryTrackingBehavior.NoTracking)
.ConfigureWarnings(w => w.Throw(RelationalEventId.QueryClientEvaluationWarning));

Categories