I am creating an invoice like this:
For signed in users, I save the invoices and the invoice units to database (one invoice has many invoice units) and for users that are not signed in, I am trying to save the data into sessions
[HttpPost]
public ActionResult Create(Invoice invoice)
{
var userId = User.Claims.FirstOrDefault(c => c.Type == "UserId")?.Value;
if (userId is not null)
{
invoice.UserId = Guid.Parse(userId.ToString());
DateTime dateTime = DateTime.Now;
invoice.DateCreated = dateTime;
foreach (var invoiceUnit in invoice.InvoiceUnits)
{
db.InvoiceUnits.Add(invoiceUnit);
}
db.Add(invoice);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
invoice.Id = Guid.NewGuid();
var invoicesFromSession = GetInvoicesFromSession();
var invoiceUnitsFromSession = GetInvoiceUnitsFromSession();
DateTime dateTime = DateTime.Now;
invoice.DateCreated = dateTime;
if (invoice is not null)
{
invoicesFromSession.Add(invoice);
HttpContext.Session.SetString("invoice", JsonSerializer.Serialize(invoicesFromSession));
foreach(var invoiceUnit in invoice.InvoiceUnits)
{
invoiceUnit.Id = new Guid();
invoiceUnit.InvoiceId = invoice.Id;
HttpContext.Session.SetString("invoiceUnit", JsonSerializer.Serialize(invoiceUnitsFromSession));
invoiceUnitsFromSession.Add(invoiceUnit);
}
}
return RedirectToAction("Index");
}
}
I am getting the invoice units from session like this:
private List<InvoiceUnit> GetInvoiceUnitsFromSession()
{
HttpContext.Session.LoadAsync();
var sessionString = HttpContext.Session.GetString("invoiceUnit");
if (sessionString is not null)
{
return JsonSerializer.Deserialize<List<InvoiceUnit>>(sessionString);
}
return Enumerable.Empty<InvoiceUnit>().ToList();
}
And then I am trying to call the function in the Edit controller
var sessionInvoices = GetInvoicesFromSession();
var sessionInvoiceUnits = GetInvoiceUnitsFromSession();
var invoiceFromDbSession = sessionInvoices.FirstOrDefault(i => i.Id == id);
List<InvoiceUnit> invoiceUnitsForInvoiceSession = new List<InvoiceUnit>();
foreach (var invoiceUnit in sessionInvoiceUnits)
{
if (invoiceUnit.InvoiceId == id)
{
invoiceUnitsForInvoiceSession.Add(invoiceUnit);
}
}
GenericModel sessionData = new GenericModel(invoiceUnitsForInvoiceSession, invoiceFromDbSession);
return View(sessionData);
From some reason tho, when I call the GetInvoiceUnitsFromSession(); in the Edit controller to retrieve the wanted invoice unit for the specific invoice, I only receive one invoice unit for each invoice (the first one I have entered). When I debug the invoiceUnitsFromSession variable in the create function, the number of units fits just fine for the specific invoice so I think there must be some problem in the way I am trying to retreive the session. Any idea what changes to make in order to retreive all of the invoice units I recieve for all invoices so I can get them in Edit controller?
The issue you see comes from this block:
foreach(var invoiceUnit in invoice.InvoiceUnits)
{
invoiceUnit.Id = new Guid();
invoiceUnit.InvoiceId = invoice.Id;
HttpContext.Session.SetString("invoiceUnit", JsonSerializer.Serialize(invoiceUnitsFromSession)); // Specifically this line
invoiceUnitsFromSession.Add(invoiceUnit);
}
Here you're writing the value for the key invoiceUnit on each repetition of the loop before you actually update the value, so at least the last line will always be missing. You would want to either change the order:
foreach(var invoiceUnit in invoice.InvoiceUnits)
{
invoiceUnit.Id = new Guid();
invoiceUnit.InvoiceId = invoice.Id;
invoiceUnitsFromSession.Add(invoiceUnit);
HttpContext.Session.SetString(
"invoiceUnit",
JsonSerializer.Serialize(invoiceUnitsFromSession));
}
or move the line that stores invoice units into the session out of the loop completely to avoid unnecessary repetition:
foreach(var invoiceUnit in invoice.InvoiceUnits)
{
invoiceUnit.Id = new Guid();
invoiceUnit.InvoiceId = invoice.Id;
invoiceUnitsFromSession.Add(invoiceUnit);
}
HttpContext.Session.SetString(
"invoiceUnit",
JsonSerializer.Serialize(invoiceUnitsFromSession));
call a list of objects from a session
Do you want the below way?
Configure your SessionExtension like below:
public static class SessionExtensions
{
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonSerializer.Serialize(value));
}
public static T? Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default : JsonSerializer.Deserialize<T>(value);
}
}
Then use methods like below:
//// your list object
List<MyClass> classCollection = new List<MyClass>();
//// To set value in session
HttpContext.Session.Set<List<MyClass>>("someKey", classCollection);
//// To Get Value from Session
List<MyClass> classCollection = HttpContext.Session.Get<List<MyClass>>("someKey");
Read Set and get Session values to know more.
Related
Trying to use Except to exclude items from a list. However the following code is not working for me i.e. my list still includes the records that it should exclude. Is there anything obvious that I am doing wrong? Is there an issue with my loops? BTW the inverse of this code works i.e correct record is inserted when RunTime matches.
[HttpPost]
public JsonResult InsertActivities([FromBody] List<MemberData> customers)
{
var mData =_context.MemberData.Select(x => x.RunTime).ToList();
foreach (var item in mData)
{
var exclude = customers.Where(x => x.RunTime == item).ToList();
var list = customers.Except(exclude).ToList();
foreach (var data in list)
{
_context.MemberData.Add(data);
}
}
int insertedRecords = _context.SaveChanges();
return Json(insertedRecords);
}
Firstly be sure you have model design like below:
public class MemberData:IEquatable<MemberData>
{
public int Id { get; set; }
public string RunTime { get; set; }
public bool Equals(MemberData other)
{
if (other is null)
return false;
return this.RunTime == other.RunTime;
}
public override bool Equals(object obj) => Equals(obj as MemberData);
public override int GetHashCode() => (RunTime).GetHashCode();
}
Then change your code like below:
public JsonResult InsertActivities([FromBody] List<MemberData> customers)
{
//hard-coded the value...
//customers = new List<MemberData>()
//{
// new MemberData(){RunTime="aa"},
// new MemberData(){RunTime="bb"},
// new MemberData(){RunTime="ee"},
//}; //hard-coded the value...
var mData = _context.MemberData.ToList();
var list = customers.Except(mData);
foreach (var item in list)
{
foreach (var data in list)
{
_context.MemberData.Add(data);
}
}
int insertedRecords = _context.SaveChanges();
return Json(insertedRecords);
}
Note:
For inserting data to database successfully, if your model contains primary key, be sure the data's(after did Except operation) keys are not duplicated with the existing database data. Or you can just do like what I did in above code that do not set value for primary key.
I have a dictionary :
public Dictionary<string, ComplexType> ListUserPerFloor { get; set; }
public class ComplexType
{
public string Id { get; set; }
public decimal Duration { get; set; }
public ComplexType(string id, decimal duration)
{
IdUser = id;
Duration = duration;
}
}
public void GetUserPerFloor(TotalTimeViewModel model)
{
var users = getUsers();
foreach (var user in users)
{
if (!model.ListUserPerFloor.Any(dic => dic.Key.Contains(user.Id)))
{
var sum = user.Duration.GetValueOrDefault(0m);
model.ListUserPerFloor.Add(user.Floor.ToString(), new ComplexType(user.Id, sum));
}
else
{
var sum = sc.Duration.GetValueOrDefault(0m);
model.ListUserPerFloor[user.Floor.ToString()].Duration = model.ListUserPerFloor[user.Floor.ToString()].Duration + sum;
}
}
}
How can I check if there is a user exit in that complexe object, if user not exit , we add , else we update that object...
( the problem here : if (!model.ListTimeUserPerFloor.Any(dic => dic.Key.Contains(user.Id)))
i want to check if user.Id exit in the Dictionary )
example
(Floor :00,{0001,15000})
(Floor :00,{0002,16000})
...
thanks in advance.
You cannot have multiple objects with the same key in the dictionary and the dictionary Dictionary<string, ComplexType> seems incorrect for string total duration.
Generally for
How can I check if there is a user exit in that complexe object, if user not exit , we add , else we update that object...
you can use ContainsKey:
// ContainsKey can be used to test keys before inserting
// them.
if (!openWith.ContainsKey("ht"))
{
openWith.Add("ht", "hypertrm.exe");
Console.WriteLine("Value added for key = \"ht\": {0}",
openWith["ht"]);
}
or TryGetValue:
// When a program often has to try keys that turn out not to
// be in the dictionary, TryGetValue can be a more efficient
// way to retrieve values.
string value = "";
if (openWith.TryGetValue("tif", out value))
{
Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
Console.WriteLine("Key = \"tif\" is not found.");
}
For your specific task I think you either want to store users per floor or only the sum of durations. Here is an example of what I mean:
var usersPerFloor = new Dictionary<int, List<ComplexType>>();
var users=getUsers();
foreach (var user in users)
{
if (!usersPerFloor.ContainsKey(user.Floor))
{
var l = new List<ComplexType>() { new ComplexType(user.Id, user.Duration)};
dictionary.Add(user.Floor, l);
}
else
{
var floorUsers = usersPerFloor[user.Floor];
var floorUser = floorUsers.FirstOrDefault(u => u.Id == user.Id);
if(floorUser == null)
{
floorUsers.Add( new ComplexType(user.Id, user.Duration));
}
else
{
floorUser.Duration += user.Duration;
}
}
I think you should use ListUserPerFloor.Values to iterate though them, e.g.
if (!model.ListUserPerFloor.Values.Any(v => v.IdUser.Equals(user.id)))
{
...
}
A little hard to say without knowing how TotalTimeViewModel model is defined, but try something similar to this:
foreach (var user in users)
{
if (model.ListUserPerFloor.GetType().GetProperties()
.Select(x => x.GetValue(model.ListUserPerFloor))
.Any(value => value.Contains(user.Id)))
{
// logic
}
else
{
// logic
}
}
You will likely need to modify this based on your implementation.
I have two classes: User and Site. User and Site have a many-to-many relationship. A Site object S has a property indicating whether or not a User U should be validated before U is added to S. To validate a User, the application retrieves validation rules from the Site and checks to see that the User's properties' values match the validation rules' values. If they all match/pass, the User is "valid" to be added to that Site.
How would you structure this relationship? My first thought is to create an intermediate class (i.e. Mediator design pattern?) that has a field of type IEnumerable<User> and Site so I can encapsulate the Site validation setting retrieval. Also, I'm thinking of adding an "IsValid" property to the User class. Is that all I need? I want to make sure things are not tightly coupled.
Thoughts?
Here's similar code I wrote up:
public class User
{
public int _userId;
public string _fname;
public string _lname;
public User(string connectionString, int id)
{
using (var dc = new DataContext(connectionString))
{
var user = dc.Users.SingleOrDefault(u => u.ID == id);
_userId = user.ID;
_fname = user.FName;
_lname = user.LName;
}
}
public bool IsValidUser(int siteId)
{
bool isValid = true;
// logic here probably won't change
var conditions = Site.GetConditions(_userId);
// e.g. checks _fname, _lname
return Site.UserMeetsConditions(_id, conditions);
}
}
public class Site
{
public int _siteId;
public List<Setting> _siteSettings;
public Site(string connectionString, int id)
{
using (var dc = new DataContext(connectionString))
{
var site = dc.Sites.SingleOrDefault(u => u.ID == id);
_siteId = site.ID;
}
}
public void SetSiteSettings(string connectionString)
{
using (var dc = new DataContext(connectionString))
{
_siteSettings = dc.SiteSettings.Select(s => s).ToList();
}
}
public bool SiteRequiresValidityCheck()
{
return _siteSettings.Any(s => s.SettingID = 100 && s.Value == true);
}
}
public Validator
{
public List<User> users;
public bool _requiresValidityCheck;
public bool UsersAreValid(int siteId)
{
bool usersAreValid = true;
if (_requiresValidityCheck)
{
foreach (var user in users)
{
if (!user.IsValid)
{
usersAreValid = false;
break;
}
}
}
return usersAreValid;
}
}
static void Main()
{
string cs = myconnectionstring;
var user1 = new User(cs, 1);
var user2 = new User(cs, 2);
List<User> users = new List<User>() { user1, user2 };
var site = new Site(cs, 10);
site.SetSiteSettings(cs);
var validator = new Validator();
validator.Users = users;
validator._requiresValidityCheck = site.SiteRequiresValidityCheck();
bool usersAreValid = validator.UsersAreValid(site._siteId);
}
If this is a POCO class or a MODEL you could use DataAnnotations on your class attributes.
Like user
[Required]
etc attributes for each attribute.
Data annotations also has support for cross attribute checking that you can implement those too.
take a look at them here:
https://msdn.microsoft.com/en-us/library/dd901590%28VS.95%29.aspx
I have stumbled upon a problem with Entity Framework this morning.
I have following code mapping a modified entity and saving it into database.
public Group Save(Group x)
{
using (var db = new HostContext())
{
db.Projects.Attach(x.Project);
if (x.ID != 0)
{
db.AttachableObjects.Attach(x);
var manager = ((IObjectContextAdapter)db).ObjectContext.ObjectStateManager;
manager.ChangeObjectState(x, EntityState.Modified);
}
else
{
db.AttachableObjects.Add(x);
}
db.SaveChanges();
return x;
}
}
I call Save method with existing group as a parameter. Group contains one user I want to add as a member.
The method finishes successfully, however the relationship is not persisted in database.
Any help is very appreciated.
EDIT: These are my classes
class User : AttachableObject
{
...
private List<Group> memberof;
[DataMember]
[InverseProperty("Members")]
public List<Group> MemberOf
{
get { return memberof; }
set { memberof = value; }
}
...
}
class Group : AttachableObject
{
...
private List<User> members;
[DataMember]
[InverseProperty("MemberOf")]
public List<User> Members
{
get { return members; }
set { members = value; }
}
...
}
EDIT2: This is where the Save method is called
public Group AcceptInvite(int id)
{
var mapper = new InviteMapper();
var userMapper = new UserMapper();
var groupMapper = new GroupMapper();
var invite = mapper.Find(id);
if (invite != null)
{
var group = groupMapper.Find(invite.GroupID);
var user = userMapper.Find(invite.InviteeID);
group.Members.Add(user);
mapper.Delete(invite.ID);
return groupMapper.Save(group);
}
return null;
}
EDIT3: My mappers
public class GroupMapper
{
public Group Find(int id)
{
using (var db = new HostContext())
{
return db.AttachableObjects
.Include("Project")
.OfType<Group>().FirstOrDefault(x => x.ID == id);
}
}
}
The rest of the mappers is the same, only using their own tables.
You are not changing the relationship info of Project, you are only setting x to modified, relationship info must be changed explicitly.
So x.Project must have some property that points back to Group, you need to set it so the change is recorded.
I am guessing that x is resurrected via some deserialization process?
Hi I have created a class to get values form my customer's account table, I have created a class for that. I want to inform AccountId and the Field of the table I want the result back (for example FirstName). What is the best way to achieve this? I got something like the below as my alternative but I can't make it work...
This is how I want to get the result of first name:
LabelFirstName.Text = Manage.GetAccount(2, "FirstName"); // where 2 is the id I informed and FirstName is the Column I want to retrieve from the table.
the result would be "John" for example.
This is what I have:
public class Manage
{
public Manage()
{
}
public static string GetAccount(int AccountId, string Field)
{
LinqSqlDataContext contextLoad = new LinqSqlDataContext();
var q = (from p in contextLoad.MyAccounts
where p.AccountId == AccountId
select p).Single();
string var = q.?? // ?? would be my Field string "FirstName" for example
return var;
}
}
Please help
Thanks
I suggest you return the Account object, and then retreive the property where you need it, like this :
public static Account GetAccount(int AccountId)
{
LinqSqlDataContext contextLoad = new LinqSqlDataContext();
var q = (from p in contextLoad.MyAccounts
where p.AccountId == AccountId
select p).Single();
return q;
}
public void myMethod()
{
var account = GetAccout(2);
var accountName = account.FirstName;
var accountNumber = account.Number;
// ... and so on
}
If this is realy not helpful, you can use reflection like mentioned in other posts.
Good luck.
string value = (string)q.GetType().GetProperty(Field).GetValue(q, null);
You can return the Object of the class
public static Object GetAccount(int AccountId)
{
LinqSqlDataContext contextLoad = new LinqSqlDataContext();
var q = (from p in contextLoad.MyAccounts
where p.AccountId == AccountId
select p).FirstOrDefault();
return q;
}
var Account = GetAccount(int AccountId) as Account;
LabelFirstName.Text = Account.FirstName;
LabelLastName.Text = Account.LastName;
You can get all the field from the object !! So task will be achievable from one database call
A DataReader might be useful in this situation:
var q = from p in contextLoad.MyAccounts
where p.AccountId == AccountId
select p;
using (var command = dc.GetCommand(q))
{
command.Connection.Open();
using (var reader = command.ExecuteReader())
{
// expecting one row
if(reader.Read())
{
return reader.GetString(reader.GetOrdinal(Value));
}
}
return null;
}