This might seem silly, but it's irritating.I'm using C# and cosmosdb sdk.
I have a document in db, lets say employee, and a corresponding Employee-class in my code.
employee
{
id: "123",
firstName : "Hans",
age : 23
}
and when updating the Employee-class in code to
public class Employee
{
public string Id{get;set}
public string FirstName{get;set}
public string LastName{get;set} // new
public int Age{get;set}
public Dictionary<string, object> OtherProperties {get;set} // also new
}
...then reading an existing document in code (GetById) and Upserting in again my document looks like this
employee
{
otherProperties : null,
id: "123"
firstName : "Hans",
lastName : null,
age : 23
}
What irritates me is that the otherProperties-property is now the first one. lastName (which was also added) happens to be exactly where it is in the class. Can I fix this somehow?
I have tested to have the property in another order in the class and also tried to change datatype to string, no difference.
Could you explain from a functional side what problem the order of properties generates?
You can decorate the class using the Newtonsoft.Json's Order on the JsonProperty: https://www.newtonsoft.com/json/help/html/JsonPropertyOrder.htm but aside from a cosmetic result, there isn't much of a functional difference.
Something like:
public class Employee
{
[JsonProperty(Order = 1)]
public string Id{get;set}
[JsonProperty(Order = 2)]
public string FirstName{get;set}
[JsonProperty(Order = 3)]
public string LastName{get;set}
[JsonProperty(Order = 4)]
public int Age{get;set}
[JsonProperty(Order = 5)]
public Dictionary<string, object> OtherProperties {get;set}
}
Related
I'm trying to save to my table Users let's say, string ID, string email, and string password. The problem is that ID must be a guid that I have to create it and save it and not SQL server. Any ideas how?
I searched but I only found how to make SQL server to create the guid.
First of all, tell Entity framework that you will generate the value of the primary key:
Use DatabaseGenerated Attribute
public class School
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Name {get; set;}
...
}
The None option prevents values from being generated by the database automatically in cases where they would otherwise be created.
Furthermore, consider to overwrite DbContext.SaveChanges(). In this procedure ask the ChangeTracker for all elements that are Added. Generate an Id for every Added element. It might be dangerous to let others generate an Id, because they might be adding a constant value or just an auto-increment.
Another possibility would be to generate it within the Add function, but if you do that, then users could change your generated Id. So the proper place is within SaveChanges:
public override int SaveChanges()
{
var addedElements = this.ChangeTracker.Entries
.Where(entry => entry.State == EntityState.Added);
foreach(var addedElement in addedElements)
{
// This will fail: the added element doesn't have a property Id:
addedElement.Id = GenerateId();
}
return base.SaveChanges();
}
For this you have to be certain that every added element has a property Id. The simplest way is to create an interface and let all your tables implement this interface:
public interface IID
{
string Id {get; set;}
}
public class School : IID {...}
public class Student : IID {...}
public class Teacher : IID {...}
public class DbContext
{
public DbSet<School> Schools {get; set;}
public DbSet<Student> Students{get; set;}
public DbSet<Teacher> Teachers {get; set;}
public override int SaveChanges()
{
var addedElements = this.ChangeTracker.Entries.Cast<IID>
.Where(entry => entry.State == EntityState.Added);
foreach(var addedElement in addedElements)
{
addedElement.Id = GenerateId(); // Every Added element implements IId
}
return base.SaveChanges();
}
private string GenerateId()
{
... // TODO: return unique ID, for instance a GUID
}
}
Here is the problem I need to solve:
I need to display a grid that contains a group of columns that are dynamic, meaning that the number can change depending on the user parameters.
I have attached a sample below as an image to illustrate:
GRID SAME IMAGE
I have these c# POCOs to keep my question simple
public class OrderItem
{
public string ProductName { get; set; }
public string Status { get; set; }
public List<CityOrderInfo> CityOrders { get; set; }
}
public class CityOrderInfo
{
public int OrderCount { get; set; }
}
I have a web api controller that is able to accept the OData request, plus other arguments that the repository accepts. However the problem is that while the parameter $orderby for ProductName and Status works, when I do "$orderby='CityOrders[1]\OrderCount asc' it fails.
public class OrdersControllers : ApiController
{
private readonly IOrdersRepository _repository;
public OrdersControllers(IOrdersRepository repository)
{
this._repository = repository;
}
public IEnumerable<OrderItem> GetOrderItems([FromUri] ODataQueryOptions<OrderItem> oDataQuery)
{
var result = this._repository.GetOrders().ToList();
var queryableData = oDataQuery.ApplyTo(result.AsQueryable());
var transformedData = queryableData as IEnumerable<OrderItem>;
return transformedData;
}
}
The reason I opted to hold the city orders in list is because I thought it would too painful to make a POCO with every city in the USA as a property so instead made it more generic.
The question is how can a sort on a property that holds a list using OData? Is this possible? I keep getting syntax error at position n. As of now I have not found an answer.
Here is my Session Class
public static class Sessions
{
public class UserSession
{
public string CurrentSelected
{
get;
set;
}
public string Req
{
get;
set;
}
public DateTime Reque
{
get;
set;
}
public List<Options> Option;
}
public class Option
{
public string Te;
public string Fe;
public string Fg;
public string DE;
}
}
I create a new session of my class
Session["SessionStats"] = new UserSession();
Then I try to add to the List
foreach(string hello in helloworld) {
Options RO = new Options();
RO.DE = item.GetDataKeyValue("DE").ToString();
RO.Fg = item.GetDataKeyValue("Fg").ToString();
RO.Fe = item.GetDataKeyValue("Fe").ToString();
RO.Te = item.GetDataKeyValue("Te").ToString();
}
This is where the error occurs
((UserSession)Session["SessionStats"]).Options.Add(RO);
RO is correctly populated but ((UserSession)Session["SessionStats"]).Option is null, I'm not sure how to add RO to this list. This has to be a list because I have like 10 RO's I need to put in this list.
After
Session["SessionStats"] = new UserSession();
you have added a new UserSession, whose Option property is null, to Session. Then, when you do
((UserSession)Session["SessionStats"]).Options.Add(RO);
you are pulling out that very same object and accessing the Option property, which is null, hence the NullReferenceException.
It looks like you are forgetting to assign something to the newly created UserOption's Option property. However, you don't seem to be using the Options you are instantiating in the foreach for anything...
You are mixing 'Option' and 'Options'. Change the class name from 'Option' to 'Options'. Then change this line:
((UserSession)Session["SessionStats"]).Options.Add(RO);
to
((UserSession)Session["SessionStats"]).Option.Add(RO);
I've gone through a couple of different tutorials with a couple approaches, but all i get is an empty datagridview. The applicable part of the code is:
public partial class ViewRoster2 : Form
{
public League vleague;
public List<Player> vlist;
public int selteam;
public ViewRoster2(League myLeague)
{
InitializeComponent();
selteam = 0;
vleague = myLeague;
vlist = vleague.playerlist;
dGrid1.DataSource = vlist;
}
From what i understand from a tutorial, the Datagrid - dGrid1 - should populate itself with columns based on object "Player" properties, and fill rows with each "Player" entry in the List<> - vlist.
But as said, all i get is a form with an empty datagridview.
Any help or push in the right direction appreciated.
I just followed the same kind of tutorial for binding a List of Objects to a DataGridView and got exactly the same issue as you.
As you didn't illustrate the definition of your "Player" object I'm not sure the cause was exactly the same, but in my case the issue was that my object definition didn't have a getter, so the DataSource was unable to retrieve the object properties to construct the View
For example, you will obtain an empty View if your define your object like this :
public class Player
{
public string name;
public int age;
public Player(string name, int age)
{
this.name = name;
this.age = age;
}
}
By adding for example { get; set; } then the View is getting populated :
public class Player
{
public string name **{ get; set; }**
public int age **{ get; set; }**
public Player(string name, int age)
{
this.name = name;
this.age = age;
}
}
I hope it will help other beginners like me ;-)
I'm working on a site where we want to include a pie chart on a page. Right now I'm working on implementing that through Reporting Services (RDLC file) with an object data source.
The SelectMethod of my object data source is a method that returns a list of business objects; lets say a List<Alpha> and Alpha has a sub object Beta with a Name property. In my report definition I have set the Category groups to be: =Fields!Beta.Value.Name this means that Alpha.Beta.Name are my pie slices. I got the following error:
An error has occurred during report processing. The Group expression for the grouping 'chart1_CategoryGroup1' contains an error: Object variable or With block variable not set.
I was able to confirm this is because Beta is nullable and was able to fix the issue by updating the object Alpha to return a new Beta() if the Beta property is null. This solution is not ideal though because there are other places in my code where I need Beta to be null if it doesn't have a value yet.
Is there a way to update the report definition to accept a null property as valid? Ideally I would like to specify the value as "Not Set" if Beta is null.
I had similar problem as yours, and I solved it using Null Object Refactoring ( many thanks to Martin Fowler's book Refactoring :)).
Here you can find nice example Null object refactoring
So you could create class NullableBeta that inherits Beta, while properties Name and e.g. IsNullable are virtual on Beta entity.
public class Beta
{
public virtual Name{ get; set;}
public virtual IsSet{ get{return true;}}
}
public class NullableBeta:Beta
{
public override Name
{
get{
return "Not Set";
}
set{}
}
public override IsSet{ get{ return false;}}
}
Now, if Beta is not set on Alfa entity, you could return instance of NullableBeta entity. In reports, you would have "Not Set" instead of empty string, and on places where you are setting Beta entity to Alfa you can check IsSet property instead of checking if Beta is null.
Hope this was helpful
I had similar problem as yours, and I solved it using Null Object Refactoring ( many thanks to Martin Fowler's book Refactoring :)). Here you can find nice example Null object refactoring
I first deal with this shortcomings of SSRS/RDLC by implementing the Null object pattern as well.
Implementing this manually is of course too much effort when more then one or two domain objects are involved.
However, since I am already using AutoMapper, #LucianBargaoanu correctly pointed out in the comments that null objects are natively supported as an opt-in feature by AutoMapper, so there is no explicit implementation needed.
I therefore use AutoMapper with its AllowNullDestinationValues, AllowNullCollections, PreserveReferences(), NullSubstitute and ForAllPropertyMaps() features, to map all my domain classes to report specific classes and substitute all null references to either null objects (when mapping domain object null references to report objects) or reasonable default values (e.g. an empty string for null strings or the default value of the underlying primitive type for Nullable<PrimitiveType>).
Here is some sample code to demonstrate the approach:
namespace Domain
{
public class MyClass
{
public int Id {get; set;}
public string Name {get; set;} // could be null
public string Code {get; set;} // could be null
public decimal? SomeNullableValue {get; set;} // could be null
public MyOtherClass OptionalOtherClass {get; set;} // could be null
}
public class MyOtherClass
{
public int OtherId {get; set;}
public string OtherName {get; set;} // could be null
public decimal? SomeOtherNullableValue {get; set;} // could be null
}
}
namespace ReportViewModels
{
[Serializable]
public class MyClass
{
public int Id {get; set;}
public string Name {get; set;} // should not be null (but empty)
public string Code {get; set;} // should not be null (but empty)
public decimal? SomeNullableValue {get; set;} // should not be null (but default(decimal))
public string CommonName
=> (Name + " " + Code).Trim();
public MyOtherClass OptionalOtherClass {get; set;} // should not be null (but a MyOtherClass null object)
}
[Serializable]
public class MyOtherClass
{
public int OtherId {get; set;}
public string OtherName {get; set;} // should not be null (but empty)
public decimal? SomeOtherNullableValue {get; set;} // should not be null (but default(decimal))
}
}
public partial class Form1 : Form
{
private Context _context;
private ReportObjectGenerator _reportObjectGenerator;
public Form1(Context context, ReportObjectGenerator reportObjectGenerator)
{
_context = context;
_reportObjectGenerator = reportObjectGenerator;
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var myDomainObjects = context.MyClass
.Include(e => e.OptionalOtherClass)
.ToList();
var myReportViewModels = _reportObjectGenerator.GetReportObjects<Domain.MyClass, ReportViewModels.MyClass>(myDomainObjects);
components ??= new System.ComponentModel.Container();
//reportViewer1.LocalReport.ReportEmbeddedResource = "MyNamespace.Report1.rdlc";
reportViewer1.LocalReport.ReportPath = "Report1.rdlc";
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(
new ReportDataSource
{
Name = "MyClassDataSet",
Value = new BindingSource(components)
{
DataMember = "MyClass",
DataSource = myReportViewModels
}
});
reportViewer1.RefreshReport();
}
}
public class ReportObjectGenerator
{
public List<TDestination> GetReportObjects<TSource, TDestination>(
IEnumerable<TSource> sourceObjects)
{
var domainNamespace = typeof(TSource).Namespace ?? throw new InvalidOperationException();
var reportNamespace = typeof(TDestination).Namespace ?? throw new InvalidOperationException();
var mapper = new MapperConfiguration(
cfg =>
{
cfg.AllowNullDestinationValues = false;
cfg.AllowNullCollections = false;
var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).ToList();
var allDomainTypes = allTypes.Where(t => t.Namespace?.StartsWith(domainNamespace) ?? false).ToList();
var allReportTypes = allTypes.Where(t => t.Namespace?.StartsWith(reportNamespace) ?? false).ToList();
foreach (var reportClassType in allReportTypes)
{
var domainClassType = allDomainTypes.Single(t => t.Name == reportClassType.Name);
cfg.CreateMap(domainClassType, reportClassType)
.PreserveReferences();
}
// If we want to set the default value of the underlying type of Nullable<UnderlyingType>
// properties in case they would be null, than AllowNullDestinationValues is not enough and we
// need to manually replace the null value here.
cfg.ForAllPropertyMaps(
pm => pm.SourceMember.GetMemberType().IsNullableType(),
(p, _) => p.NullSubstitute ??= Activator.CreateInstance(p.SourceMember.GetMemberType().GetTypeOfNullable()));
})
.CreateMapper();
return mapper.Map<IEnumerable<TSource>, List<TDestination>>(sourceObjects);
}
}