Check This Code Sniplet out.
using (AttendanceDataContext db = new AttendanceDataContext())
{
var attendance = db.attendpunches.Select(at => new RawEmployeeCheckInOutInfo
{
CheckTime = at.punchtime.Value,
Direction = ((AttendanceDirection)at.direction.Value).ToString()
});
...
AttendanceDirection is enum Which is...
public enum AttendanceDirection : int
{
CheckIn = 1,
CheckOut = 2
}
The Problem is The Direction = ((AttendanceDirection)at.direction.Value).ToString() is always returning the byte value.
I suspect the problem is that the ToString is being effectively performed at the database side, which doesn't know the enum names. Try this:
var attendance = db.attendpunches
.Select(at => new { CheckTime = at.punchtime.Value,
Direction = at.direction.Value })
.AsEnumerable() // Do the rest of the query in-process...
.Select(at => new RawEmployeeCheckInOutInfo {
CheckTime = at.CheckTime,
Direction = ((AttendanceDirection) at.Direction).ToString()
});
Related
my question is simple but I got stuck with something. Can you tell me how can I reduce 2 select into 1 select LINQ in c#? I am using CloudNative.CloudEvents NuGet package for cloud-native events.
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent())
.Select(_ =>
new CloudEvent()
{
Type = _.EventType,
Subject = _.Subject,
Source = _.Source,
Data = _
});
input is a parameter from cosmosDbTrigger it`s type : IReadOnlyList
OrderDocument.cs
public class OrderDocument
{
public string Id { get; private set; }
public string Json { get; private set; }
public OrderDocument(string id, string json)
{
Id = id;
Json = json;
}
public OrderEvent ToOrderEvent() => OrderEventHelper.ToOrderEvent(Json);
}
OrderEventHelper.cs
public static OrderEvent ToOrderEvent(string json)
{
ArgumentHelper.ThrowIfNullOrEmpty(json);
var orderEvent = JsonConvert.DeserializeObject<OrderEvent>(json);
var eventDefinition = OrderEvents.EventDefinitions.SingleOrDefault(_ => _.EventType == orderEvent.EventType);
return eventDefinition == null
? orderEvent
: new OrderEvent(
orderEvent.Id,
orderEvent.Source,
orderEvent.EventType,
orderEvent.Subject,
orderEvent.DataContentType,
orderEvent.DataSchema,
orderEvent.Timestamp,
JsonConvert.DeserializeObject(orderEvent.Payload.ToString(), eventDefinition.PayloadType),
orderEvent.TraceId);
}
linq extensions are basically for loops in the background. If you want to perform multiple actions against a list, perhaps making your own simple for loop where you can manage that yourself would work.
Your code:
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent())
.Select(_ =>
new CloudEvent()
{
Type = _.EventType,
Subject = _.Subject,
Source = _.Source,
Data = _
});
could be changed to:
// our result set, rather than the one returned from linq Select
var results = new List<CloudEvent>();
foreach(var x in input){
// create the order event here
var temporaryOrderEvent = new OrderDocument(x.Id, x.ToString()).ToOrderEvent();
// add the Cloud event to our result set
results.Add(new CloudEvent()
{
Type = temporaryOrderEvent .EventType,
Subject = temporaryOrderEvent .Subject,
Source = temporaryOrderEvent .Source,
Data = temporaryOrderEvent
});
}
where you then have a result list to work with.
If you wanted to keep it all in linq, you could instead perform all of your logic in the first Select, and ensure that it returns a CloudEvent. Notice here that you can employ the use of curly brackets in the linq statement to evaluate a function rather than a single variable value:
var orderEvents = input
.Select(x =>
{
// create the order event here
var temporaryOrderEvent = new OrderDocument(x.Id, x.ToString()).ToOrderEvent();
// return the Cloud event here
return new CloudEvent()
{
Type = temporaryOrderEvent .EventType,
Subject = temporaryOrderEvent .Subject,
Source = temporaryOrderEvent .Source,
Data = temporaryOrderEvent
};
});
How about putting conversion to OrderEvent and using ToCloudEvent in the same Select?
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent().ToCloudEvent())
public class OrderEvent
{
public CloudEvent ToCloudEvent()
{
new CloudEvent()
{
Type = this.EventType,
Subject = this.Subject,
Source = this.Source,
Data = this
};
}
}
I am building a website that does has a chat component to it. The code below receives from a stored procedure a list of messages with a lots of different paramaters. 1 of those is if a message is in reply to another, and if that is the case, duplicate the message that is being replied to over the message answer. If the message that was being replied to was also an answer to a previous message do the same ect. Now my issue is that I have not been able to figure out how to automate this part of the code without nesting if into one another until a point where I hope users won't reply in the same chain anymore.
To rephrase it, I go in a list in inverse order and check if the ReplyingTo is not null.
I then copy the row that has the same ID and ReplyingTo 1 row higher than the current row.
I then confirm that this new row has a ReplyingTo
If it does I copy that object 2 row higher than the current one.
and I would continue this way until I reached a certain point that the users would not reach.
If anyone got an idea on how to proceed I would be highly gracious. I have put an example of the type of data that would be given to this function below.
for (int i = publicChatCountList.Count-1 ; i > -1; i--)
{
if (publicChatCountList[i].ReplyingTo.HasValue)
{
Chat_Dto chatItem = new Chat_Dto();
long? ReplyingToId = publicChatCountList[i].ReplyingTo;
chatItem = publicChatCountList.Find(x => x.Id == ReplyingToId);
publicChatCountList.Insert(i+1, new Chat_Dto() {Text = chatItem.Text, IsPublic = chatItem.IsPublic, IsApproved = chatItem.IsApproved, ReplyingTo = chatItem.ReplyingTo });
publicChatCountList[i+1].Duplicate = true;
if (chatItem.ReplyingTo.HasValue)
{
Chat_Dto chatItem2 = new Chat_Dto();
long? ReplyingToId2 = chatItem.ReplyingTo;
chatItem2 = publicChatCountList.Find(x => x.Id == ReplyingToId2);
publicChatCountList.Insert(i + 2, new Chat_Dto() { Text = chatItem2.Text, IsPublic = chatItem2.IsPublic, IsApproved = chatItem2.IsApproved, ReplyingTo = chatItem2.ReplyingTo });
publicChatCountList[i + 2].Duplicate = true;
}
}
}
If I understood you correctly maybe running something like this to recursively get all replies would work:
private void Replies(Chat_Dto_List publicChatCountList,int i)
{
if (publicChatCountList[i].ReplyingTo.HasValue)
{
Chat_Dto chatItem = new Chat_Dto();
long? ReplyingToId = publicChatCountList[i].ReplyingTo;
chatItem = publicChatCountList.Find(x => x.Id == ReplyingToId);
publicChatCountList.Insert(i + 1, new Chat_Dto() { Text = chatItem.Text, IsPublic = chatItem.IsPublic, IsApproved = chatItem.IsApproved, ReplyingTo = chatItem.ReplyingTo });
publicChatCountList[i + 1].Duplicate = true;
if (chatItem.ReplyingTo.HasValue)
{
Replies(publicChatCountList, publicChatCountList.FindIndex(x => x.Id == chatItem.ReplyingTo))
}
}
}
I'm working with a third part service of my client that is providing me a list of products and services, which is a little bit of a mess.
The list will return all of the services for the product but the product repeats itself, for example:
The product A has the service A and the product A also has the service B so, when i receive the list i will get two products A with services A and B
What i need to do is to group all of the products to get only one with all of it's services and i have done so but i'm worried about performance because i think my solution isn't the 'best' one:
var productsNormalized = products.Data.AsEnumerable().Select(x => new ProdutoSSO
{
CodigoServico = int.Parse(string.IsNullOrEmpty(x["CodigoServico"].ToString()) ? "0" : x["CodigoServico"].ToString()),
CodigoPeca = int.Parse(string.IsNullOrEmpty(x["CodigoPeca"].ToString()) ? "0" : x["CodigoPeca"].ToString()),
CodigoFamilia = int.Parse(string.IsNullOrEmpty(x["CodigoFamilia"].ToString()) ? "0" : x["CodigoFamilia"].ToString()),
Familia = x["Familia"].ToString(),
Servico = x["Servico"].ToString(),
Peca = x["Peca"].ToString(),
Hash = x["Hash"].ToString(),
Valor = decimal.Parse(string.IsNullOrEmpty(x["Valor"].ToString()) ? "0" : x["Valor"].ToString())
})
.GroupBy(x => new { x.CodigoPeca, x.CodigoFamilia, x.Familia, x.Peca })
.Select(x => new ProdutoGroup
{
Produto = new Produto
{
CodigoPeca = x.Key.CodigoPeca,
CodigoFamilia = x.Key.CodigoFamilia,
Familia = x.Key.Familia,
Peca = x.Key.Peca
},
Servicos = x.Select(y => new ProdutoServico
{
CodigoServico = y.CodigoServico,
Hash = y.Hash,
Servico = y.Servico,
Valor = y.Valor
}).ToList()
});
Is there a better way to achieve this or this is as good as it gets?
Using Aggregate you could do something like this (assuming you are starting with a list of ProdutoSSO, which might not be entirely necessary):
var productsNormalized = productoSSOs
.Aggregate(new Dictionary<Produto,List<ProdutoServico>>(ProductoComparer),
(p,c) => {
var product = new Produto
{
CodigoPeca = c.CodigoPeca,
CodigoFamilia = c.CodigoFamilia,
Familia = c.Familia,
Peca = c.Peca
};
var service = new ProdutoServico
{
CodigoServico = c.CodigoServico,
Hash = c.Hash,
Servico = c.Servico,
Valor = c.Valor
};
if (!p.ContainsKey(product))
{
p[product] = new List<ProductoServico>() { service };
}
else
{
p[product].Add(service);
}
return p;
});
Where ProductoComparer is an IEqualityComparer<Producto> (or alternatively you could implement Equals and GetHashCode in Producto, or you could just generate a key some other way - concatenating fields together, for example).
This is obviously untested since I don't have the original classes or data.
This would give you a Dictionary<Producto, List<ProductoServico>> which might be all you need, or you can easily transform it into an IEnumerable<ProdutoGroup> if you want.
Most of the time I retrieve multiple records so I would end up doing this
var rpmuser = new List<rpm_scrty_rpm_usr>();
I have my List collection of properties from poco
So I typically use select new in my Linq statement
Then I use a foreach and loop over the records in which the List would get model.Add(new instance in each loop)
However , do I really need to be doing all this looping to populate?
Bigger question when i have a single record should I be needing to even do a loop at all?
public bool UpdateAllUsers(string user, string hash, string salt)
{
bool status = false;
var rpmuser = new rpm_scrty_rpm_usr();
var query = (from t in db.rpm_usr
.Where(z => z.usr_id == "MillXZ")
select new
{
t.usr_id,
t.usr_lnm,
t.usr_pwd,
t.usr_fnm,
t.salt,
t.inact_ind,
t.lst_accs_dtm,
t.lst_pwd_chg_dtm,
t.tel,
t.wwid,
t.email_id,
t.dflt_ste_id,
t.apprvr_wwid,
t.chg_dtm,
t.chg_usr_id,
t.cre_dtm,
t.cre_usr_id,
});
foreach(var s in query)
{
rpmuser.wwid = s.wwid;
rpmuser.usr_pwd = s.usr_pwd;
rpmuser.usr_lnm = s.usr_lnm;
rpmuser.usr_id = s.usr_id;
rpmuser.usr_fnm = s.usr_fnm;
rpmuser.tel = s.tel;
rpmuser.salt = s.salt;
rpmuser.lst_pwd_chg_dtm = rpmuser.lst_pwd_chg_dtm;
rpmuser.lst_accs_dtm = s.lst_accs_dtm;
rpmuser.inact_ind = s.inact_ind;
rpmuser.email_id = s.email_id;
rpmuser.apprvr_wwid = s.apprvr_wwid;
rpmuser.chg_dtm = s.chg_dtm;
rpmuser.chg_usr_id = s.chg_usr_id;
rpmuser.cre_usr_id = s.cre_usr_id;
rpmuser.dflt_ste_id = s.dflt_ste_id;
rpmuser.cre_dtm = s.cre_dtm;
}
DateTime dateTime = DateTime.Now;
try
{
rpmuser = db.rpm_usr.Find(rpmuser.usr_id);
rpmuser.usr_pwd = hash;
rpmuser.salt = salt;
db.SaveChanges();
status = true;
}
catch (Exception ex)
{
status = false;
}
return status;
}
I am not exactly sure what you want. Your method says Update All, but only seems to be attempting to update one record. So why don't you just do this?
try
{
var rpmuser = db.rpm_usr.Single(z => z.usr_id == "MillXZ");
rpmuser.usr_pwd = hash;
rpmuser.salt = salt;
db.SaveChanges();
status = true;
}
catch (Exception ex)
{
status = false;
}
You have a lot of redundant declarations unless I am missing something. In the case of the list you will do something like this:
var query = db.rpm_usr.Where(z => z.usr_id == "...some string...");
foreach(var item in query)
{
rpmuser.usr_pwd = ...some value...;
rpmuser.salt = ...some value...;
}
db.SaveChanges();
I can't stress this enough, Murdock's answer is absolutely the right way to fix the code you've shown. You are writing way too much code for what you're trying to accomplish.
However, to answer your question about whether you need to loop in other situations, you can get away from having to loop by doing the projection into a new type as part of your LINQ-to-Entities query. The looping still happens, you just don't see it.
var query = db.rpm_usr
.Where(z => z.usr_id == "MillXZ")
.AsEnumerable()
.Select(z => new rpm_scrty_rpm_usr()
{
usr_id = z.usr_id,
usr_lnm = z.usr_lnm,
// etc...
});
You would then finish the query off with a .Single(), .SingleOrDefault(), or .ToList() depending on whether you expected exactly one, one or zero, or a list. For example, in this case if you might find one or zero users with the name "MillXZ" you would write the following.
var query = db.rpm_usr
.Where(z => z.usr_id == "MillXZ")
.AsEnumerable()
.Select(z => new rpm_scrty_rpm_usr()
{
usr_id = z.usr_id,
usr_lnm = z.usr_lnm,
// etc...
})
.SingleOrDefault();
On my WPF Grid I am populating the following properties. The last two are coming from another table. I would like to get the mapping rule from another table where sourceelementid in the transaction table equals the id of the messagefield table
public List<MessageFieldViewModel> GetAllViewModelMsgFields()
{
messageFieldVModel = messageField.GetAllMessageField().Select(msgFields => new MessageFieldViewModel
{
Id = msgFields.Id,
Code = msgFields.Code,
Name = msgFields.Name,
Position = msgFields.Position,
Length = msgFields.Length,
IsMapped = (transactionRuleList.Any(tr=> tr.SourceElementId ==msgFields.Id)),
MappingRule = transactionRuleList.Where(mapRule => mapRule.MappingRule.Any(tr=> tr.SourceElementId ==msgFields.Id)),
})
.ToList();
return messageFieldVModel;
}
but the Mapping rule column throws error. Can some one help me ?
Here is a solution :
transactionRuleList = transationRuleViewModel.GetAllTranslationRules();
messageFieldVModel = messageField.GetAllMessageField().Select(msgFields => new MessageFieldViewModel
{
Id = msgFields.Id,
Code = msgFields.Code,
Name = msgFields.Name,
Position = msgFields.Position,
Length = msgFields.Length,
IsMapped = (transactionRuleList.Any(tr => tr.SourceElementId == msgFields.Id)),
MappingRule = transactionRuleList.Any(mapRule => mapRule.SourceElementId == msgFields.Id)?transactionRuleList.First(mapRule => mapRule.SourceElementId == msgFields.Id).MappingRule:null