I know that this code is not good and maybe it's stupid question but can anybody explain me why it works in this way?
I have this simple class
public class Customer
{
public string Name { get; set; }
}
And I have next method with Action delegate
private Customer GetCustomer(Action<Customer> action)
{
var model = new Customer { Name = "Name 1" };
action?.Invoke(model);
return model;
}
Then I execute this method with delegate and write into console model.Name
var model = GetCustomer(c => c = new Customer { Name = "Name 2" });
Console.WriteLine(model.Name);
I expected to get "Name 2". But I get "Name 1" - which is value of the class defined inside method. I understand that to get what I want - I could write code in this way:
var model = GetCustomer(c => c.Name = "Name 2");
Console.WriteLine(model.Name);
And everything will be ok. But why my first implementation doesn't work?
I would be thankful a lot if somebody explain me this.
c in your lambda is only assigning to the parameter, its not assinging it back to model in GetCustomer.
Lambda expression in your case compiles into a method.
This is the same, why this code won't change c.Name:
// code below is equivalent of
// c => c = new Customer { Name = "Name 2" }
private void Foo(Customer c)
{
// c will be changed inside method,
// but will remain unchanged outside it
c = new Customer { Name = "Name 2" };
}
In your lambda expression, you are just saying that c and model are pointing to the same reference. And then you are changing the reference of c. At the end model is still referencing to the previous instance. This is the equivalent code of what you are trying to do:
var model = new Customer { Name = "Name 1" };
var c = model;
c = new Customer { Name = "Name 2" };
But, model.Name is still Name1.
You can change your code as if you want to change one of hte properties:
var model = GetCustomer(c => c.Name = "Name2");
Console.WriteLine(model.Name);
var model = GetCustomer(c => c.Name = "Name 2");
instead of:
var model = GetCustomer(c => c = new Customer { Name = "Name 2" });
Why? Because you want to do the changes on the same instance transferred in the new function (implements the delegate). If you create a new instance of Customer in new function (c) then it would do the changes on the new instance of Customer that won't be valid when c ends.
Same here but with List.
Related
I have an class called message, inside which I have a IEnumerable called copies.
I need to create a new Recipient class object with the copies content.
In order to do that, I created a Recipient list, then interacting on copies using ForEach method; But I took so much code lines, and it doesn't feel good for me. There is a way to do that using LINQ methods?
I'll put below what I've done so far.
CODE USING FOREACH (PROPERLY WORKING)
var recipientListWithForEach = new List<Recipient>();
foreach (var item in message.Copies)
{
recipientListWithForEach.Add(new Recipient
{
EmailAddress = new EmailAddress
{
Address = item
}
});
}
CODE USING LINQ (NOT WORKING, IDK WHY)
var recipientListWithLINQ = new List<Recipient> {
message.Copies.Select(item => new Recipient {
EmailAddress = new EmailAddress {
Address = item
}
});
};
Giving the error message:
not possible convert from "System.Collections.Generic.IEnumerable<Microsoft.Graph.Recipient>" to "Microsoft.Graph.Recipient"
Actually problem that you have not used proper constructor for List
// working
new List<T>(items)
Following is list initialisation syntax, which accepts not an IEnumerable but single items separated by coma.
// bad
new List<T> {items}
// working
new List<T> {item1, item2}
So, just correct your code
var recipientListWithLINQ = new List<Recipient> (
message.Copies.Select(item => new Recipient {
EmailAddress = new EmailAddress {
Address = item
}
));
};
But LINQ query should be simplier
var recipientListWithLINQ =
message.Copies.Select(item => new Recipient {
EmailAddress = new EmailAddress {
Address = item
}
)
.ToList();
You're doing a little bit too much work! .Select returns the list you need. Wrapping that list in a Recipient constructor is not needed.
var recipientListWithLINQ =
message.Copies.Select(item => new Recipient {
EmailAddress = new EmailAddress {
Address = item
}
});
Update per comment: since you need single item, you don't really need IEnumerable. Just pick first item from Copies and construct your Recipient. And probably pick a better name for a variable?
var item = message.Copies.First();
var recipientListWithLINQ = new Recipient {
EmailAddress = new EmailAddress {
Address = item
}
};
Original answer:
You need to convert your IEnumerable to List with ToList()
var recipientListWithLINQ = message.Copies.Select(item => new Recipient {
EmailAddress = new EmailAddress {
Address = item
}
}).ToList();
If I have a GUID for a record, but I do not know whether it is an Account or a Contact, how can I retrieve this record and identify its type?
For example, I can retrieve a specified type like so:
var serviceAppointment = organizationService.Retrieve(
"serviceappointment",
serviceActivityGuid,
new ColumnSet(true));
However, if I do not know what type of record it is, how can I retrieve it and identify its type?
Something like this:
var myEntity = organizationService.Retrieve(
"????",
myEntityGuid,
new ColumnSet(true));
If you reference the DLaB.Xrm from Nuget, you could write this like this:
bool isAccount = service.GetEntitiesById<Account>(customerId).Count == 1;
If you wanted to actually get the actual values, you could do this.
var customerId = System.Guid.NewGuid();
var entity = service.GetEntitiesById<Account>(customerId).FirstOrDefault() ??
service.GetEntitiesById<Contact>(customerId).FirstOrDefault() as Entity;
if (entity != null)
{
var account = entity as Account; // will be null if the Guid was for a contact
var contact = entity as Contact; // will be null if the Guid was for an account
}
You cannot search by the GUID alone.
You need both the GUID and the entity logical name.
Whenever you retrieve a entity reference using code, c# or javascript, the object will include the entity logical name
Update to try to find an account with a given ID:
Guid Id = // Your GUID
IOrganizationService serviceProxy = // Create your serivce proxy
var accountQuery = new QueryExpression
{
EntityName = "account",
TopCount = 1,
Criteria =
{
Conditions =
{
new ConditionExpression("accountid", ConditionOperator.Equal, Id)
}
}
}
var response = serviceProxy.RerieveMultiple(accountQuery);
if(null == response.Entities.FirstOrDefault())
{
//No Account Record Found
}
If you only need to distinguish between with Account and Contact and want to make sure the record really still exists, you could also use their CustomerAddress, LEFT OUTER JOINing both, Account and Contact:
var query = new QueryExpression
{
EntityName = "customeraddress",
ColumnSet = new ColumnSet("customeraddressid"),
TopCount = 1,
Criteria = new FilterExpression
{
Conditions =
{
// limit to Address 1
new ConditionExpression("addressnumber", ConditionOperator.Equal, 1),
// filter by "anonymous" GUID
new ConditionExpression("parentid", ConditionOperator.Equal, myEntityGuid),
},
},
LinkEntities =
{
new LinkEntity
{
EntityAlias = "acc",
Columns = new ColumnSet("name"),
LinkFromEntityName = "customeraddress",
LinkFromAttributeName = "parentid",
LinkToAttributeName = "accountid",
LinkToEntityName = "account",
JoinOperator = JoinOperator.LeftOuter
},
new LinkEntity
{
EntityAlias = "con",
Columns = new ColumnSet("fullname"),
LinkFromEntityName = "customeraddress",
LinkFromAttributeName = "parentid",
LinkToAttributeName = "contactid",
LinkToEntityName = "contact",
JoinOperator = JoinOperator.LeftOuter
},
},
};
... will allow you to retrieve whichever, Account or Contact in one go:
var customer = service.RetrieveMultiple(query).Entities.FirstOrDefault();
... but require to access their fields through AliasedValues:
string customername = (customer.GetAttributeValue<AliasedValue>("acc.name") ?? customer.GetAttributeValue<AliasedValue>("con.fullname") ?? new AliasedValue("whatever", "whatever", null)).Value as string;
... which can make reading a lot of attributes a little messy.
I know this is an old question, but I thought I would add something in case someone stumples upon this in the future with a problem similar to mine. In this case it might not be particularly the same as OP has requested.
I had to identify whether an entity was one or the other type, so I could use one method instead of having to write standalone methods for each entity. Here goes:
var reference = new EntityReference
{
Id = Guid.NewGuid(),
LogicalName = "account" //Or some other logical name - "contact" or so.
}
And by passing it into the following method the type can be identified.
public void IdentifyType(EntityReference reference)
{
switch(reference.LogicalName)
{
case Account.EntityLogicalName:
//Do something if it's an account.
Console.WriteLine($"The entity is of type {nameof(Account.EntityLogicalName)}."
case Contact.EntityLogicalName:
//Do something if it's a contact.
Console.WriteLine($"The entity is of type {nameof(Contact.EntityLogicalName)}."
default:
//Do something if neither of above returns true.
Console.WriteLine($"The entity is not of type {nameof(Account.EntityLogicalName)} or {nameof(Contact.EntityLogicalName)}."
}
}
In the following code that returns a list:
public List<Customer> GeAllCust()
{
var results = db.Customers
.Select(x => new { x.CustName, x.CustEmail, x.CustAddress, x.CustContactNo })
.ToList()
return results;
}
I get an error reporting that C# can't convert the list:
Error: Cannot implicitly convert type System.Collections.Generic.List<AnonymousType#1> to System.Collections.Generic.List<WebApplication2.Customer>
Why is that?
Here's a screenshot showing some additional information that Visual Studio provides in a tooltip for the error:
Is it right way to return some columns instead of whole table....?
public object GeAllCust()
{
var results = db.Customers.Select(x => new { x.CustName, x.CustEmail, x.CustAddress, x.CustContactNo }).ToList();
return results;
}
When you look the code:
x => new { ... }
This creates a new anonymous type. If you don't need to pull back only a particular set of columns, you can just do the following:
return db.Customers.ToList();
This assumes that Customers is an IEnumerable<Customer>, which should match up with what you are trying to return.
Edit
You have noted that you only want to return a certain subset of columns. If you want any sort of compiler help when coding this, you need to make a custom class to hold the values:
public class CustomerMinInfo
{
public string Name { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public int? ContactNumber { get; set; }
}
Then change your function to the following:
public List<CustomerMinInfo> GetAllCust()
{
var results = db.Customers.Select(x => new CustomerMinInfo()
{
Name = x.CustName,
Email = x.Email,
Address = x.Address,
ContactNumber = x.CustContactNo
})
.ToList();
return results;
}
This will work, however, you will lose all relationship to the database context. This means if you update the returned values, it will not stick it back into the database.
Also, just to repeat my comment, returning more columns (with the exception of byte arrays) does not necessarily mean longer execution time. Returning a lot of rows means more execution time. Your function is returning every single customer in the database, which when your system grows, will start to hang your program, even with the reduced amount of columns.
You are selecting to an anonymous type, which is not a Customer.
If you want to do (sort of) this, you can write it like this:
return db.Customers.Select(x => new Customer { Name = x.CustName, Email = x.CustEmail, Address = x.CustAddress, ContactNo = x.ContactNo }).ToList();
This assumes the properties on your Customer object are what I called them.
** EDIT ** Per your comment,
If you want to return a subset of the table, you can do one of two things:
Return the translated form of Customer as I specified above, or:
Create a new class for your business layer that only has only those four fields, and change your method to return a List<ShrunkenCustomer> (assuming ShunkenCustomer is the name that you choose for your new class.)
GetAllCust() is supposed to return a List of Customer, Select New will create a list of Anonymous Types, you need to return a list of Customer from your query.
try:
var results = db.Customers.Select( new Customer{CustName = x.CustName}).ToList(); //include other fields
I guess Customer is a class you have defined yourself?
The my suggestion would be to do something like the following:
var results = db.Customers.Select(x => new Customer(x.Custname, x.CustEmail, x.CustAddress, x.CustContactNo)).ToList();
The reason is that you are trying to return a list of Customer but the results from your link is an anonymous class containing those four values.
This would of course require that you have a constructor that takes those four values.
Basically whatever u got in var type, loop on that and store it in list<> object then loop and achieve ur target.Here I m posting code for Master details.
List obj = new List();
var orderlist = (from a in db.Order_Master
join b in db.UserAccounts on a.User_Id equals b.Id into abc
from b in abc.DefaultIfEmpty()
select new
{
Order_Id = a.Order_Id,
User_Name = b.FirstName,
Order_Date = a.Order_Date,
Tot_Qty = a.Tot_Qty,
Tot_Price = a.Tot_Price,
Order_Status = a.Order_Status,
Payment_Mode = a.Payment_Mode,
Address_Id = a.Address_Id
});
List<MasterOrder> ob = new List<MasterOrder>();
foreach (var item in orderlist)
{
MasterOrder clr = new MasterOrder();
clr.Order_Id = item.Order_Id;
clr.User_Name = item.User_Name;
clr.Order_Date = item.Order_Date;
clr.Tot_Qty = item.Tot_Qty;
clr.Tot_Price = item.Tot_Price;
clr.Order_Status = item.Order_Status;
clr.Payment_Mode = item.Payment_Mode;
clr.Address_Id = item.Address_Id;
ob.Add(clr);
}
using(ecom_storeEntities en=new ecom_storeEntities())
{
var Masterlist = en.Order_Master.OrderByDescending(a => a.Order_Id).ToList();
foreach (var i in ob)
{
var Child = en.Order_Child.Where(a => a.Order_Id==i.Order_Id).ToList();
obj.Add(new OrderMasterChild
{
Master = i,
Childs = Child
});
}
}
I tried following code with following designed model.
First call to SaveChanges() is succeed but not when it comes to second call.
I have already worked 18 hours on this and can't figure out what is the problem.
Specially when I can achieve the code goal manually with MSSQL server explorer !
Can anyone provide me a solution ?
var mc = new Model1Container1();
mc.Categories.Add(new Category() { Text = "Laptop" });
mc.Categories.Add(new Category() { Text = "TV" });
mc.SaveChanges();
var cat = mc.Categories.Where(c => c.Text == "Laptop").FirstOrDefault();
CKey ck = new CKey() { Key = "RAM" };
cat.CKeys.Add(ck);
for (int i = 1; i < 100; i++)
{
var ia = new Item() { Text = "MSI GX780-R", Category = cat };
ia.CProperties.Add(new CProperty() { Value = "4GB", CKey = ck });
mc.Items.Add(ia);
mc.SaveChanges();
}
You are trying to associate the same CKey instance to 100 instances of CProperty, but according to the graph of multiplicities, a given instance of CKey can only be associated to at most 1 CProperty.
Either create a new instance of CKey in each iteration of the loop, or modify your schema.
I am trying to get information from a database, convert it to a list and return the CustomerList. This first bit of code works fine. The second example is where I’m trying to accomplish the same thing except the fields are coming from my database. What’s wrong with what I’m doing and how can I make this work? The second piece of code works elsewhere in my project but not here.
private SchoolIn.Models.CustomerList CreateCustomerList()
{
return new SchoolIn.Models.CustomerList()
{
new SchoolIn.Models.Customer { Id = 1, Name = "Patrick", Address = "Geuzenstraat 29", Place = "Amsterdam" },
new SchoolIn.Models.Customer{ Id = 2, Name = "Fred", Address = "Flink 9a", Place = "Rotterdam" },
new SchoolIn.Models.Customer { Id = 3, Name = "Sjonnie", Address = "Paternatenplaats 44", Place = "Enkhuizen" },
new SchoolIn.Models.Customer { Id = 4, Name = "Henk", Address = "Wakerdijk 74", Place = "Utrecht" },
new SchoolIn.Models.Customer { Id = 5, Name = "Klaas", Address = "Paternatenplaats 44", Place = "Plaantan" }
};
}
private SchoolIn.Models.CustomerList CreateCustomerList()
{
return new SchoolIn.Models.CustomerList()
{
SchoolInDB db = new SchoolIn.Models.SchoolInDB();
var courseprogresses = db.CourseProgresses.Include(c => c.Course).Include(c => c.Teacher);
return View(courseprogresses.ToList());
};
}
First things first the second code is invalid C#. So I suppose it doesn't event compile. You cannot use such expressions in an object initialization syntax. Please learn C# before getting into ASP.NET MVC.
The other problem is that your method is private and you are attempting to return View which is something that you do in a controller action. The view method returns an ActionResult whereas your method return type is SchoolIn.Models.CustomerList which once again is wrong.
So move this into some controller action where you would instantiate your database access context and then perform the query and return the model to the corresponding view for display:
public class HomeController: Controller
{
...
public ActionResult CreateCustomerList()
{
SchoolInDB db = new SchoolIn.Models.SchoolInDB();
var courseprogresses = db
.CourseProgresses
.Include(c => c.Course)
.Include(c => c.Teacher)
.ToList();
return View(courseprogresses);
}
}
and if you wanted to keep this into a separate method:
private List<SchoolIn.Models.CourseProgress> CreateCustomerList()
{
SchoolInDB db = new SchoolIn.Models.SchoolInDB();
return db
.CourseProgresses
.Include(c => c.Course)
.Include(c => c.Teacher)
.ToList();
}
In your first function you are returning actual list while in second function you are not returning list, instead you have returned the View with model as a list. So for it you need to return View Result viz. ActionResult.
Hope it helps