linq issue with creating relationships - c#

Seems I have a slight problem with my linq, I have a datacontract for Groups and I have a seperate datacontract for messages. Messages can be part of a Group. However when I update a message record its not reflected when I list the group information, the message is still the same for that group. But yet the update is reflected when I directly list messages?
This is how I add a message to a group:
//lists for reference:
List<Group> Groups = new List<Group>();
List<Message> messages = new List<Message>();
//not sure the below method is correct for adding a message to a group
public void AddMessagetoGroup(string group, string messageID, string message)
{
var result = Groups.Where(n => String.Equals(n.GroupName, group)).FirstOrDefault();
var result1 = messages.Where(n => String.Equals(n.MessageID, messageID)).FirstOrDefault();
if (result != null)
{
result.GroupMessages.Add(new Message() { MessageID = messageID, GroupMessage = message });
}
if (result1 != null)
{
result1.MessageGroup.Add(new Group() { GroupName = group });
}
}
Seriously dont understand whats going on, if I add the message to the group any changes I make to the message should be reflected. The only thing I can think of is its adding a new instance of the already existing message, which means my update method is only copying the message, but where is this new copyed record even held. If its to difficult to fix how could I update the message that has been copyedTo/added to the group instead (cheap workaround)?

Assuming that a Group can have Messages and a Message can have Groups, you are trying to maintain 5 things:
The list of all Groups List<Group> Groups = ...
The list of all Messages List<Message> messages = ...
The messages for each Group List<Message> GroupMessages... in Group
The groups for each message List<Group> MessageGroup... in Message
The actual message to send to the group updated in several places
From what I can see it's the last one that is not being maintained correctly:
In AddMessagetoGroup you associate a 'new' Message to the Group.GroupMessages. This is a new instance of a class and won't be updated automatically when you update other Message instances. Just because two messages have the same MessageId doesn't mean they are the same instance.
In UpdateMessage you change a particular message but only in the messages list. This doesn't point to the same message in the group list.
All in all, you need a refactor to really get your code to what you want it to do. The way I see it is that you want to keep groups and messages separate, and reference once from the other rather than create copies.
First, the master list:
List<Group> Groups = new List<Group>();
List<Message> Messages = new List<Message>();
Secondly, creating or updating a message (you don't have the create part yet):
public Message CreateOrUpdateMessage(string messageID, string groupMessage)
{
var findmessage = Messages.Where(s => s.MessageID == messageID).FirstOrDefault();
if (findmessage != null)
{
findmessage.GroupMessage = groupMessage;
}
else
{
findmessage = new Message() { MessageID = messageID, GroupMessage = groupMessage};
Messages.Add(findmessage);
}
return findmessage;
}
Note how this takes care of adding this message to the Messages list. This is the only function that should add or change messages.
And finally adding messages to a group (note I don't worry about adding groups here):
public void AddMessagetoGroup(string group, string messageID, string message)
{
var findmessage = CreateOrUpdateMessage(messageID, message);
var findgroup = Groups.Where(n => String.Equals(n.GroupName, group)).FirstOrDefault();
if (findgroup != null)
{
if (findgroup.GroupMessages.Where(m => m.MessageID == messageID).Count() == 0)
{
findgroup.GroupMessages.Add(findmessage);
findmessage.MessageGroup.Add(findgroup);
}
}
}
Note that this function will also create the message, and ensure there are no duplicates in either Messages in total or Messages for any particular group.

Related

How to make code object oriented by removing if checks?

I have a windows service which checks for date and send notification remainder to user for a payment for which user has subcribed for a service.
Its a monthly payment service system for which user has to make a payment at the end of the month and for that system sends 2 remainder notification to user :
1) Before N days from deadline if payment not made.
2) Send remainder on deadline if payment not received.
So below are the conditions based on which notifications are send to User as well as Administrator :
Code :
public enum PaymentStatusEnum
{
Ask_For_Payment = 0,
Payment_Remainder_Sent = 1,
Full_Payment_Done = 2,
Payment_Not_Done = 3,
}
public class ServicePaymentModel
{
public int PaymentId { get; set; }
public string Email { get; set; }
public int PaymentStatus { get; set; }
public string AdminId { get; set; }
public int NoOfDaysPassed { get; set; }
public decimal DueAmount { get; set; }
public decimal PaymentMade { get; set; }
}
public void SendNotification()
{
int daysBeforeDeadline = 10;
int deadlineDays = 20;
var paymentModel = new PaymentModel
{
Today = 10/5/2019,
DaysBeforeDeadline = daysBeforeDeadline,
DeadlineDays = deadlineDays
};
//Get all the payments whose daysBeforeDeadline or deadlineDays condition is met.
//For eg: If some users subscription started from 1/5/2019 and Todays date is 10/5/2019 then this users will be will be fetched because of daysBeforeDeadline.
//For eg: If some users subscription started from 20/4/2019 and Todays date is 10/5/2019 then this users will be will be fetched because deadlineDays condition
List<ServicePaymentModel> payments = MyRepo.GetPayments(paymentModel);
if (payments != null && payments.Count == 0)
return;
UserPayment userPayment = null;
foreach (var payment in payments)
{
try
{
if (payment.DueAmount > 0) //Payment not done
{
if (paymentModel.DeadlineDays == payment.NoOfDaysPassed
&& payment.PaymentStatus == (int)PaymentStatusEnum.Payment_Remainder_Sent) // payment not made on deadline
{
userPayment = new UserPayment
{
PaymentId = payment.Id,
PaymentStatus = (int)PaymentStatusEnum.Payment_Not_Done
}
SendNotificationToUser(payment);//method handles email sending and different email template for user
SendNotificationToAdmin(payment)//method handles email sending and different email template for Admin telling him about which user payment has not been received
}
else if (paymentModel.DaysBeforeDeadline == payment.NoOfDaysPassed
&& payment.PaymentStatus == (int)PaymentStatusEnum.Ask_For_Payment)//payment not done after N days
{
userPayment = new UserPayment
{
PaymentId = payment.Id,
PaymentStatus = (int)PaymentStatusEnum.Payment_Remainder_Sent
}
SendNotificationToUser(payment);//method handles email sending and different email template for user
SendNotificationToAdmin(payment)//method handles email sending and different email template for Admin telling him about which user payment has not been received
}
}
else if (payment.DueAmount == 0) // payment done
{
userPayment = new UserPayment
{
PaymentId = payment.Id,
PaymentStatus = (int)PaymentStatusEnum.Full_Payment_Done
}
if ((paymentModel.DeadlineDays == payment.NoOfDaysPassed
&& payment.PaymentStatus == (int)PaymentStatusEnum.Ask_For_Payment)// payment made on deadline
{
SendNotificationToUser(payment);//method handles email sending and different email template for user along with message and body
SendNotificationToAdmin(payment)//method handles email sending and different email template for admin along with message and body
}
else if (paymentModel.DaysBeforeDeadline == payment.NoOfDaysPassed
&& payment.PaymentStatus == (int)PaymentStatusEnum.Ask_For_Payment)//payment done before XX days
{
SendNotificationToAdmin(payment)//method handles email sending and different email template for admin along with message and body
}
}
PaymentRepo.UpdateUserPaymentStatus(userPayment);
}
catch (Exception ex)
{
//do nothing and continue processing other payment
}
}
}
I have seen this Plural sight video where Author - Zoran Horvat is saying that we can turn almost any If checks to object oriented solution and as you can see my code contains alot of if checks and tomorrow if more Conditions are added than this If will grow tremendously creating maintainance night mare.
All my Conditions and PaymentStatus are being handled based on If checks but here I am not getting how to turn this if conditions in to object oriented solution and whether it would be really possible or not in this case.
So is it possible to make this code object oriented by removing if checks or any better way to handle this checks?
public void SendNotificationRefactor2()
{
int daysBeforeDeadline = 10;
int deadlineDays = 20;
var paymentModel = new PaymentModel
{
Today = 10 / 5 / 2019,
DaysBeforeDeadline = daysBeforeDeadline,
DeadlineDays = deadlineDays
};
//Get all the payments whose daysBeforeDeadline or deadlineDays condition is met.
//For eg: If some users subscription started from 1/5/2019 and Todays date is 10/5/2019 then this users will be will be fetched because of daysBeforeDeadline.
//For eg: If some users subscription started from 20/4/2019 and Todays date is 10/5/2019 then this users will be will be fetched because deadlineDays condition
List<ServicePaymentModel> payments = MyRepo.GetPayments(paymentModel);
if (payments != null && payments.Count == 0)
return;
//UserPayment userPayment = null;
foreach (var payment in payments)
{
try
{
// Breaking this out into a method is optional, really, because there's little chance it'll
HandlePayment(paymentModel, payment);
}
catch (Exception ex)
{
// SWALLOWING EXCEPTIONS IS AN INDESCRIBABLY BAD IDEA. DON'T DO THIS.
}
}
}
protected void HandlePayment(PaymentModel paymentModel, ServicePaymentModel payment)
{
var userPayment = new UserPayment
{
PaymentId = payment.Id
};
if (payment.DueAmount > 0) //Payment not done
{
if (paymentModel.DeadlineDays == payment.NoOfDaysPassed)
{
if (payment.PaymentStatus == (int)PaymentStatusEnum.Payment_Remainder_Sent)
{
userPayment.PaymentStatus = (int)PaymentStatusEnum.Payment_Not_Done;
}
else if (payment.PaymentStatus == (int)PaymentStatusEnum.Ask_For_Payment)//payment not done after N days
{
userPayment.PaymentStatus = (int)PaymentStatusEnum.Payment_Remainder_Sent;
}
SendNotificationToUser(payment);//method handles email sending and different email template for user
SendNotificationToAdmin(payment);//method handles email sending and different email template for Admin telling him about which user payment has not been received
}
}
else if (payment.DueAmount == 0) // payment done
{
userPayment.PaymentStatus = (int)PaymentStatusEnum.Full_Payment_Done;
if (paymentModel.DeadlineDays == payment.NoOfDaysPassed)
{
if (payment.PaymentStatus == (int)PaymentStatusEnum.Ask_For_Payment)
{
SendNotificationToUser(payment);//method handles email sending and different email template for user along with message and body
SendNotificationToAdmin(payment);//method handles email sending and different email template for admin along with message and body
}
else if (payment.PaymentStatus == (int)PaymentStatusEnum.Ask_For_Payment)
{
SendNotificationToAdmin(payment);//method handles email sending and different email template for admin along with message and body
}
}
}
PaymentRepo.UpdateUserPaymentStatus(userPayment);
}
First off: focus on the goal. The belief that making something more OO makes it better is a belief structure I call "object happiness disorder". Remember, the purpose of OO code is to lower the costs of large programs worked on by large teams, by making it very clear what service is provided by a piece of code, what its public interface is, and how it interacts with other components. It's not a general-purpose technique for making small code better.
Your goal should not be to make the program "more OO"; it should be to make it lower cost, so ask yourself "what are the costs associated with this program?" Where are you spending money, remembering that your salary is probably most of that money?
For example:
We're spending too much time updating the code when business processes change.
If that's the problem then I would make the program more OO, but not by "replace condition with polymorphism". Just because it is polymorphic does not make it OO. What makes it OO is we have identified fundamental concepts in the business domain and encapsulated those concepts into objects that only have to change when the business process changes.
The key thing to look at is your extremely helpful diagram that shows:
What exogenous condition triggers a state change?
What are the state changes?
What action is associated with a state change?
So, codify that. Make a base class EventTrigger. You've already got a type representing states. Make a class called EventAction. Make a class Condition. And now what is our process?
for each trigger in eventTriggers
if any trigger condition is met
execute all trigger actions
Now we're down to a single if statement, like you wanted. Now you can write one class for each condition, and one class for each action, and triggers tie them together.
If you want to change the action associated with a particular trigger, you change it in one place, not in a mass of spaghetti code.
Also, this technique is amenable to many other improvements. You can easily add logging; logging is just another action. You can make compositions of actions; make an action that takes two actions and runs them both. And so on.
You could even make a configuration document that looks like:
TRIGGER PaymentReceivedTrigger HAS CONDITION AskForPayment WITH ACTIONS SetFullPayment, EmailAdmin
…
And now you can set up your whole system based on a config file instead of writing C# code.
But what if that is not the problem? What if the problem is:
We're spending too much time tracking down bugs
Or
Our performance is bad and we do not know why
Or
We're completely tied to one database vendor but they are too expensive; how can we lower the cost of switching back ends?
Or any of a million other things? In those cases, you don't want to waste any time building an OO business process engine; you want to concentrate on the problem that is actually costing you money, and figure out what lowers that cost.

EasyNetQ - How to retry failed messages & persist RetryCount in message body/header?

I am using EasyNetQ and need to retry failed messages on the original queue. The problem is: even though I successfully increment the TriedCount variable (in the body of every msg), when EasyNetQ publishes the message to the default error queue after an exception, the updated TriedCount is not in the msg! Presumably because it just dumps the original message to the error queue without the consumer's changes.
The updated TriedCount works for in-process republishes, but not when republished through EasyNetQ Hosepipe or EasyNetQ Management Client. The text files Hosepipe generates do not have the TriedCount updated.
public interface IMsgHandler<T> where T: class, IMessageType
{
Task InvokeMsgCallbackFunc(T msg);
Func<T, Task> MsgCallbackFunc { get; set; }
bool IsTryValid(T msg, string refSubscriptionId); // Calls callback only
// if Retry is valid
}
public interface IMessageType
{
int MsgTypeId { get; }
Dictionary<string, TryInfo> MsgTryInfo {get; set;}
}
public class TryInfo
{
public int TriedCount { get; set; }
/*Other information regarding msg attempt*/
}
public bool SubscribeAsync<T>(Func<T, Task> eventHandler, string subscriptionId)
{
IMsgHandler<T> currMsgHandler = new MsgHandler<T>(eventHandler, subscriptionId);
// Using the msgHandler allows to add a mediator between EasyNetQ and the actual callback function
// The mediator can transmit the retried msg or choose to ignore it
return _defaultBus.SubscribeAsync<T>(subscriptionId, currMsgHandler.InvokeMsgCallbackFunc).Queue != null;
}
I have also tried republishing myself through the Management API (rough code):
var client = new ManagementClient("http://localhost", "guest", "guest");
var vhost = client.GetVhostAsync("/").Result;
var errQueue = client.GetQueueAsync("EasyNetQ_Default_Error_Queue",
vhost).Result;
var crit = new GetMessagesCriteria(long.MaxValue,
Ackmodes.ack_requeue_true);
var errMsgs = client.GetMessagesFromQueueAsync(errQueue,
crit).Result;
foreach (var errMsg in errMsgs)
{
var pubRes = client.PublishAsync(client.GetExchangeAsync(errMsg.Exchange, vhost).Result,
new PublishInfo(errMsg.RoutingKey, errMsg.Payload)).Result;
}
This works but only publishes to the error queue again, not on the original queue. Also, I don't know how to add/update the retry information in the body of the message at this stage.
I have explored this library to add headers to the message but I don't see if the count in the body is not being updated, how/why would the count in the header be updated.
Is there any way to persist the TriedCount without resorting to the Advanced bus (in which case I might use the RabbitMQ .Net client itself)?
Just in case it helps someone else, I eventually implemented my own IErrorMessageSerializer (as opposed to implementing the whole IConsumerErrorStrategy, which seemed like an overkill). The reason I am adding the retry info in the body (instead of the header) is that EasyNetQ doesn't handle complex types in the header (not out-of-the-box anyway). So, using a dictionary gives more control for different consumers. I register the custom serializer at the time of creating the bus like so:
_defaultBus = RabbitHutch.CreateBus(currentConnString, serviceRegister => serviceRegister.Register<IErrorMessageSerializer>(serviceProvider => new RetryEnabledErrorMessageSerializer<IMessageType>(givenSubscriptionId)));
And just implemented the Serialize method like so:
public class RetryEnabledErrorMessageSerializer<T> : IErrorMessageSerializer where T : class, IMessageType
{
public string Serialize(byte[] messageBody)
{
string stringifiedMsgBody = Encoding.UTF8.GetString(messageBody);
var objectifiedMsgBody = JObject.Parse(stringifiedMsgBody);
// Add/update RetryInformation into objectifiedMsgBody here
// I have a dictionary that saves <key:consumerId, val: TryInfoObj>
return JsonConvert.SerializeObject(objectifiedMsgBody);
}
}
The actual retrying is done by a simple console app/windows service periodically via the EasyNetQ Management API:
var client = new ManagementClient(AppConfig.BaseAddress, AppConfig.RabbitUsername, AppConfig.RabbitPassword);
var vhost = client.GetVhostAsync("/").Result;
var aliveRes = client.IsAliveAsync(vhost).Result;
var errQueue = client.GetQueueAsync(Constants.EasyNetQErrorQueueName, vhost).Result;
var crit = new GetMessagesCriteria(long.MaxValue, Ackmodes.ack_requeue_false);
var errMsgs = client.GetMessagesFromQueueAsync(errQueue, crit).Result;
foreach (var errMsg in errMsgs)
{
var innerMsg = JsonConvert.DeserializeObject<Error>(errMsg.Payload);
var pubInfo = new PublishInfo(innerMsg.RoutingKey, innerMsg.Message);
pubInfo.Properties.Add("type", innerMsg.BasicProperties.Type);
pubInfo.Properties.Add("correlation_id", innerMsg.BasicProperties.CorrelationId);
pubInfo.Properties.Add("delivery_mode", innerMsg.BasicProperties.DeliveryMode);
var pubRes = client.PublishAsync(client.GetExchangeAsync(innerMsg.Exchange, vhost).Result,
pubInfo).Result;
}
Whether retry is enabled or not is known by my consumer itself, giving it more control so it can choose to handle the retried msg or just ignore it. Once ignored, the msg will obviously not be tried again; that's how EasyNetQ works.

Add same member many time together with add card trello but don't work

Add same member many times to gather with add card trello but don't work
PROBLEM
When I input an same username, for example
{ "adwin", "adwin", "robert", "dave"}
If first adwin finishes loop add member is ok, then second adwin time to add.
The code exit loop and stop working.
and
When I input usernames aren't in the board or username is fake.
{ "hghg$*#hgh", "us7s5209hf9", "8shjd76dhj3" }
When add card finish and come to add Member It's stop working and exit program.
It's not working loop to finish to add another username.
Plan
I think add Member to a board before add into a card will work but it not work again.
#r"Manatee.Trello.dll"
#r"Manatee.Json.dll"
using System.Net;
using System.ComponentModel;
using System.Drawing;
using System.Windows;
using Manatee.Trello;
using Manatee.Json;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string Appkey = "df45ee60b0ff10c19377354490f7054b";
string Token = "6af303020a7a4d24d9cf5a1dd8adf2e5ff95c46888b0371c0b2dba45b2a32d7d";
string BoardID = "5b40363293193091c1ba5013";
string ListID = "5b40363293193091c1ba5015";
string name ="CardAddMember";
string description ="desccccc";
string duedate ="2019-08-04";
string iscomplete =true;
string[] user = {"userinboard","notusername","userinboard"};
try
{
DateTime duedatetime = DateTime.Parse(duedate);//time
bool torf = Boolean.Parse(iscomplete);//finish work check
TrelloAuthorization.Default.AppKey = Appkey;
TrelloAuthorization.Default.UserToken = Token;
ITrelloFactory factory = new TrelloFactory();
var List = factory.List(ListID);
var Board = factory.Board(BoardID);
//var MemberType = factory.Board();
char[] commaSeparator = new char[] { ',' };
string[] authors = username.Split(commaSeparator, StringSplitOptions.None);
var card = await List.Cards.Add(name, description, null, duedatetime, torf, null, null);//add card to trello
foreach (string author in authors){
var Member = factory.Member(author);
await Board.Memberships.Add(Member); // Add member in a board but cant add <<<<<<<<<????????
await card.Members.Add(Member); //add member in card
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
return response;
}
catch //find some err [example not find user]
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
}
What should I do ?
Cr.marc_s edit world
You're going to need to check the members before you add them. Trello returns an error when you attempt to add a member to a board/card but that member already exists. This, in turn, will cause Manatee.Trello to throw an exception.
Additionally, a member must belong to a board before they can be assigned to a card.
Checking for these members first should resolve your problem.
await Board.Memberships.Refresh(); // this will fetch all of the members of the board
foreach (string author in authors){
var Member = factory.Member(author);
if (!Board.Memberships.Any(m => m.Member == Member))
await Board.Memberships.Add(Member);
if (!Card.Members.Contains(Member))
await card.Members.Add(Member);
}
This should resolve the problems you're seeing.
Lastly, when you catch an exception, it's helpful to specify the exception and possible print out or log the result. Trello's pretty good at returning error messages with their failure responses, and Manatee.Trello will include them in its TrelloInteractionExceptions.

How to determine if a complete batch of Async requests have failed?

A 3rd party has supplied an interface which allows me to search their database for customers and retrieve their details. Eg. Pictures, date of birth etc.
I imported their WSDL into Visual Studio and am using the Async methods to retrieve the customer details.
MyClient Client = new MyClient();
Client.FindCustomersCompleted += FindCustomersCompleted;
Client.GetCustomerDetailsCompleted += GetCustomerDetailsCompleted;
Client.FindCustomersAsync("Jones");
Below are the two events which deal with the responses.
void FindCustomersCompleted(object sender, FindCustomersCompletedEventArgs e)
{
foreach(var Cust in e.Customers)
{
Client.GetCustomerDetailsAsync(Cust.ID);
}
}
void GetCustomerDetailsCompleted(object sender, GetCustomerDetailsCompletedEventArgs e)
{
// Add the customer details to the result box on the Window.
}
So lets assume that my initial search for "Jones" returns no results or causes an error. Its fairly straight forward to tell the user that there was an error or no results found as I will only receive a single response.
However if i say get 50 results for "Jones" then i make 50 GetCustomerDetailsAsync calls and get 50 responses.
Lets say that something goes wrong on the server side and i don't get any valid responses. Each GetCustomerDetailsCompleted event will receive an error/timeout and i can determine that that individual response has failed.
What is the best way to determine that All of my responses have failed and i need to inform the user that there has been a failure?
Alternatively what if 1 out of 50 succeeds?
Should i keep track of my requests and flag them as successful as i receive the response?
Should i keep track of my requests and flag them as successful as i
receive the response?
This is also how I manage multiple requests. Flag if the returned result is without fault and track the flags, evaluating after each return if you already processed all returns. I do not of another way.
I would start by converting Event-based Asynchronous Pattern model to Task based. This would allow to use built in await/async keywords resulting in much easier to use code.
Here is a simple implementation: https://stackoverflow.com/a/15316668/3070052
In your case I would not update UI on each event but gathered all the information in a single variable and only displayed only when I get all the results.
Here is a code to get you going:
public class CustomerDetails
{
public int Id {get; set;}
public string Name {get; set;}
}
public class FindCustomersResult
{
public FindCustomersResult()
{
CustomerDetails = new List<CustomerDetails>();
}
public List<CustomerDetails> CustomerDetails {get; set;}
}
public class ApiWrapper
{
public Task<FindCustomersResult> FindCustomers(string customerName)
{
var tcs = new TaskCompletionSource<FindCustomersResult>();
var client = new MyClient();
client.FindCustomersCompleted += (object sender, FindCustomersCompletedEventArgs e) =>
{
var result = new FindCustomersResult();
foreach(var customer in e.Customers)
{
var customerDetails = await GetCustomerDetails(customer.ID);
result.CustomerDetails.Add(customerDetails);
}
tcs.SetResult(result);
}
client.FindCustomersAsync(customerName);
return tcs.Task;
}
public Task<CustomerDetails> GetCustomerDetails(int customerId)
{
var tcs = new TaskCompletionSource<CustomerDetails>();
var client = new MyClient();
client.GetCustomerDetailsCompleted += (object sender, GetCustomerDetailsCompletedEventArgs e) =>
{
var result = new CustomerDetails();
result.Name = e.Name;
tcs.SetResult(result);
}
client.GetCustomerDetailsAsync(customerId);
return tcs.Task;
}
}
Then you call this by:
var api = new ApiWrapper();
var findCustomersResult = await api.FindCustomers("Jones");
This would fail if any request fails.
PS. I wrote this example in notepad, so bear with me if it does not compiles or contains syntax errors. :)

Preserving DataContext, long running operation within Iterating

Following actions needs to be performed:
get a view from the database of users that needs to recieve an e-mail
send this email
update the records of the usres with a timestamp the email was send.
This code does as described above but in the wrong order (rough sketch/needs refactoring):
public class MailMessageController
{
public static IEnumerable<Invitation> GetInvitations()
{
using (boDataContext context = new boDataContext())
{
// the table where the timestamps have to be set
Table<Computer> computer = context.GetTable<Computer>();
// the view that contains the users email addresses
Table<Invitation> report = context.GetTable<Invitation>();
// get the view from the database
IEnumerable<Invitation> items = report.AsEnumerable<Invitation>();
foreach (Invitation item in items)
{
// update the timestamp (not good, the e-mail hasn't been sent)
Computer c = computer.FirstOrDefault(
i => i.ComputerID == item.ComputerID
);
if (c != null)
{
c.DateInvited = DateTime.Now;
}
yield return item;
}
context.SubmitChanges(); // <-- this should commit the changes
}
}
I send e-mails from this collections via:
foreach(Invitation item in MailMessageController.GetInvitations())
{
if (SendMessage(item)) // <<-- bool if message was sent successfully
{
// here I want to update the database with the timestamp
}
}
So I need to update the database with a timestamp after the e-mail was send succesfully.
But it seems that I can't get around the fact that I need to create a context for every instance I need to update.
So this is more of a design issue. How can I get the view from the database, send emails and update the timestamp in the most fluent and less-cost manner?
How about updating the timestamps outside the loop?
var timeStamps = new List<Tuple<DateTime, int>>();
foreach(Invitation item in MailMessageController.GetInvitations())
{
if (SendMessage(item)) // <<-- bool if message was sent successfully
{
timeStamps.Add(new Tuple<DateTime, int>(DateTime.Now, item.ID);
}
}
UpdateTimeStamps(timeStamps);

Categories