Why on gods earth will the APFile.Id not deserialize correct ???
I have a simple class APFile - which I try to deserialize - for some reason it will not deserialize the Id - and I cannot see where its going wrong :(
using System;
using Newtonsoft.Json;
namespace ActionShared
{
[Serializable]
public class APFile
{
public APFile()
{
}
/// <summary>
/// File id
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// The id of entity that the file is attached to.
/// </summary>
// [JsonProperty("type")]
[JsonIgnore]
public int Type { get; set; }
/// <summary>
/// The file name including the extension.
/// </summary>
[JsonProperty("filename")]
public string Filename { get; set; }
/// <summary>
/// The mime type of the file.
/// </summary>
[JsonIgnore]
public string Mimetype { get; set; }
/// <summary>
/// The size of the file in bytes.
/// </summary>
//[JsonProperty("size")]
[JsonIgnore]
public int Size { get; set; }
/// <summary>
/// The unique id of the file creator's profile.
/// </summary>
//[JsonProperty("creator_id")]
[JsonIgnore]
public int Creator { get; set; }
/// <summary>
/// The unique id of the file creator's profile.
/// </summary>
//[JsonProperty("creator_name")]
[JsonIgnore]
public string CreatorName { get; set; }
/// <summary>
/// The date and time when the file was uploaded.
/// </summary>
// [JsonProperty("created_at")]
[JsonIgnore]
public DateTime CreatedAt { get; set; }
/// <summary>
/// The date and time when the file was last updated.
/// </summary>
// [JsonProperty("updated_at")]
[JsonIgnore]
public DateTime UpdatedAt { get; set; }
/// <summary>
/// A link to download the file.
/// </summary>
//[JsonProperty("url")]
[JsonIgnore]
public string Url { get; set; }
}
}
public void Do()
{
string a = "{\"id\":910,\"filename\":\"image.jpg\"}";
var b = JsonConvert.DeserializeObject<APFile>(a);
// b.Id = 0 and b.Filename = "image.jpg"
}
plz copy your json responce and convert into C# class file to http://json2csharp.com/
public home()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
PostRequest(this, "http://propertyworld.in/app/property.php?");
}
public async static void PostRequest(home instance, string URL)
{
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("action", "property_list"),
});
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(URL, formContent);
//json variable is over responce
var json = await response.Content.ReadAsStringAsync();
MyJsonConvertedclass record = JsonConvert.DeserializeObject<MyJsonConvertedclass>(json);
ObservableCollection<ModelClass.infoClass> ls = new ObservableCollection<ModelClass.infoClass> { };
foreach (var point in record.records)
{
ls.Add(new ModelClass.infoClass
{
info1 = Stringclass.rs + " " + point.property.price,
info2 = point.property.title.ToUpper(),
url = record.image_url + point.property.image
});
}
instance.newProp.ItemsSource = ls;
//instance.yourControllname which is declares in your xaml like
}
Related
am looking to create a Dto class using the following JSON am facing an issue without the hardCode root numbers: "1" and "2" as a JsonPropertyNames it's not working, am using Dictionary object to collect the data, the Dto class: StorageData_v1 has to elemenate hardcode PropertyNam values use dictionary object like was referered/used :
**I want to eliminate the below hardcoded values and collect them into Dictionary object like was used property: public Dictionary<string, StorageData> Data { get; set; }**
**Note: I have tried using JsonPropertyTagNames =new Object[]{"1",2"} as well, but it didn't work**
/// <summary>
/// DBK Data Details
/// </summary>
[JsonProperty(PropertyName = "2")]
public DataInfo DataDetails2 { get; set; }
/// <summary>
/// DBK Data Details
/// </summary>
[JsonProperty(PropertyName = "1")]
public DataInfo DataDetails { get; set; }
JSON string:
{
"apiVersion": 1,
"data": {
"738": {
"1": {
"juris": "test",
"entity": "11",
"storage": {
"$podDbkRawBase64": "test"
},
"instance": "1",
"calcJobId": "13d1c32252f24795",
"formIndex": "10",
"ReturnId": "b93c4acaa0c0"
}
},
"463": {
"1": {
"juris": "test",
"entity": "test",
"storage": {
"$podRawBase64": "test2"
},
"instance": "1",
"calcJobId": "13d1c32252f",
"formIndex": "4",
"ReturnId": "b93c4aca"
}
}
}
}
**Dto class:**
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace TestModels.Dto
{
/// <summary>
/// Unit data object
/// </summary>
public class StorageData_v1
{
/// <summary>
/// Input Screen Unit
/// </summary>
[JsonProperty(PropertyName = "apiVersion")]
public string ApiVersion { get; set; }
/// <summary>
/// Input Screen fields
/// </summary>
[JsonProperty(PropertyName = "data")]
public Dictionary<string, StorageData> Data { get; set; }
}
/// <summary>
/// DBK storage Information for DTO
/// </summary>
public class StorageData
{
/// <summary>
/// DBK Data Details
/// </summary>
[JsonProperty(PropertyName = "1")]
public DataInfo DataDetails { get; set; }
/// <summary>
/// DBK Data Details
/// </summary>
[JsonProperty(PropertyName = "2")]
public DataInfo DataDetails2 { get; set; }
}
public class DataInfo
{
/// <summary>
/// Jurisditction
/// </summary>
[JsonProperty(PropertyName = "juris")]
public string Jurisdiction { get; set; }
/// <summary>
/// DBK Entity type
/// </summary>
[JsonProperty(PropertyName = "entity")]
public string Entity { get; set; }
/// <summary>
/// DBK data Instance
/// </summary>
[JsonProperty(PropertyName = "instance")]
public string Instance { get; set; }
/// <summary>
/// DBK data Calc JobId
/// </summary>
[JsonProperty(PropertyName = "calcJobId")]
public string CalcJobId { get; set; }
/// <summary>
/// DBK data Index
/// </summary>
[JsonProperty(PropertyName = "formIndex")]
public string FormIndex { get; set; }
/// <summary>
/// Return Id
/// </summary>
[JsonProperty(PropertyName = "ReturnId")]
public string ReturnId { get; set; }
/// <summary>
/// Data fields
/// </summary>
[JsonProperty(PropertyName = "storage")]
public Storage Storage { get; set; }
}
public class Storage
{
/// <summary>
/// Base 64 data
/// </summary>
[JsonProperty(PropertyName = "$podRawBase64")]
public string PodRawBase64 { get; set; }
}
}
You can use:
public class Storage
{
[JsonProperty("$podDbkRawBase64")]
public string PodDbkRawBase64 { get; set; }
[JsonProperty("$podRawBase64")]
public string PodRawBase64 { get; set; }
}
public class Root
{
public int apiVersion { get; set; }
[JsonProperty(PropertyName = "data")]
public Dictionary<string, Dictionary<string, DataItem>> DataItems { get; set; }
}
public class DataItem
{
public string juris { get; set; }
public string entity { get; set; }
public string instance { get; set; }
public string calcJobId { get; set; }
public string fromIndex { get; set; }
public string ReturnId { get; set; }
public Storage storage { get; set; }
}
And you can deserialize you object like this:
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
I have a project that has a login screen. When the user logs in the Controller calls another Class that I am using as a data Access class. This Class called the stored procedure to verify if the user is valid and pulls back all the user information and loads it into a UserModel. This works as I just have the data access method return a bool. So then I am logged in. But the information is not staying or is never stored in my model. I have been researching this and working off and on for this for weeks. I am hoping another set of eyes will help show me what I am missing. Thanks.
Here is my Model
public class UserModel
{
/// <summary>
/// Holds the current username.
/// </summary>
public string UserName {get;set;}
/// <summary>
/// Holds the First Name of the user.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Holds the last name of the user.
/// </summary>
public string LastName { get; set; }
/// <summary>
/// Holds the users Date of Birth.
/// </summary>
public string UserDOB { get; set; }
/// <summary>
/// Holds the users Email Address
/// that was provided.
/// </summary>
public string Email { get; set; }
/// <summary>
/// Holds the current Password of the user.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Holds the Date the account was created.
/// </summary>
public DateTime CreationDate { get; set; }
/// <summary>
/// Holds the PK of the type of user,
/// Admin, Standard, Promotional
/// </summary>
public int UserType { get; set; }
}
Here is my Data Access
public bool UserLogin(string userName, string Password)
{
bool userFound = false;
const string Query = #"GetUserLogin";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(Query, connection)
{
CommandType = CommandType.StoredProcedure
};
command.Parameters.AddWithValue("#UserName", userName);
command.Parameters.AddWithValue("#Password", Password);
using (SqlDataReader reader = command.ExecuteReader())
{
reader.Read();
userModel.UserName = reader["UserName"].ToString();
userModel.FirstName = reader["FirstName"].ToString();
userModel.LastName = reader["LastName"].ToString();
userModel.Email = reader["Email"].ToString();
userModel.UserDOB = reader["UserDOB"].ToString();
if (reader == null)
{
userFound = false;
}
else
{
userFound = true;
}
}
}
return userFound;
}
This is my User Controller
public class UserController : Controller
{
private UserLoginDataAccess dataAccess = new UserLoginDataAccess();
// GET: /Login/
[HttpGet]
public IActionResult Login()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public IActionResult Login(UserModel model)
{
bool isLoggedIn;
isLoggedIn = dataAccess.UserLogin(model.UserName, model.Password);
if (isLoggedIn)
{
return View("Dashboard");
}
else
{
return View();
}
}
}
Firstly, this is never not null:
if (reader == null)
Secondly: where / how is userModel defined? If that is a field on the controller, then note that it jsn't persisted anywhere between requests. You need to use other approaches here. Usually an auth cookie of some kind.
Thirdly: I'm horrified to know whether you're doing a flat password compare in the DB; please let it be hashed...
Fourthly: writing your own security code is almost never a good idea. There are login providers that get it right. I recommend using them.
Fifthly: you should test whether Read() returned true or not - although frankly I think I'd recommend offloading all of this DB code to something like Dapper.
I have following JSON string which is received from an external party.
{
"team":[
{
"v1":"",
"attributes":{
"eighty_min_score":"",
"home_or_away":"home",
"score":"22",
"team_id":"500"
}
},
{
"v1":"",
"attributes":{
"eighty_min_score":"",
"home_or_away":"away",
"score":"30",
"team_id":"600"
}
}
]
}
My mapping classes:
public class Attributes
{
public string eighty_min_score { get; set; }
public string home_or_away { get; set; }
public string score { get; set; }
public string team_id { get; set; }
}
public class Team
{
public string v1 { get; set; }
public Attributes attributes { get; set; }
}
public class RootObject
{
public List<Team> team { get; set; }
}
The question is that I don't like the Attributes class name and the attributes field names in the Team class. Instead, I want it to be named TeamScore and also to remove _ from the field names and give proper names.
JsonConvert.DeserializeObject<RootObject>(jsonText);
I can rename Attributes to TeamScore, but if I change the field name (attributes in the Team class), it won't deserialize properly and gives me null. How can I overcome this?
Json.NET - Newtonsoft has a JsonPropertyAttribute which allows you to specify the name of a JSON property, so your code should be:
public class TeamScore
{
[JsonProperty("eighty_min_score")]
public string EightyMinScore { get; set; }
[JsonProperty("home_or_away")]
public string HomeOrAway { get; set; }
[JsonProperty("score ")]
public string Score { get; set; }
[JsonProperty("team_id")]
public string TeamId { get; set; }
}
public class Team
{
public string v1 { get; set; }
[JsonProperty("attributes")]
public TeamScore TeamScores { get; set; }
}
public class RootObject
{
public List<Team> Team { get; set; }
}
Documentation: Serialization Attributes
If you'd like to use dynamic mapping, and don't want to clutter up your model with attributes, this approach worked for me
Usage:
var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new CustomContractResolver();
this.DataContext = JsonConvert.DeserializeObject<CountResponse>(jsonString, settings);
Logic:
public class CustomContractResolver : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }
public CustomContractResolver()
{
this.PropertyMappings = new Dictionary<string, string>
{
{"Meta", "meta"},
{"LastUpdated", "last_updated"},
{"Disclaimer", "disclaimer"},
{"License", "license"},
{"CountResults", "results"},
{"Term", "term"},
{"Count", "count"},
};
}
protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}
Adding to Jacks solution. I need to Deserialize using the JsonProperty and Serialize while ignoring the JsonProperty (or vice versa). ReflectionHelper and Attribute Helper are just helper classes that get a list of properties or attributes for a property. I can include if anyone actually cares. Using the example below you can serialize the viewmodel and get "Amount" even though the JsonProperty is "RecurringPrice".
/// <summary>
/// Ignore the Json Property attribute. This is usefule when you want to serialize or deserialize differently and not
/// let the JsonProperty control everything.
/// </summary>
/// <typeparam name="T"></typeparam>
public class IgnoreJsonPropertyResolver<T> : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }
public IgnoreJsonPropertyResolver()
{
this.PropertyMappings = new Dictionary<string, string>();
var properties = ReflectionHelper<T>.GetGetProperties(false)();
foreach (var propertyInfo in properties)
{
var jsonProperty = AttributeHelper.GetAttribute<JsonPropertyAttribute>(propertyInfo);
if (jsonProperty != null)
{
PropertyMappings.Add(jsonProperty.PropertyName, propertyInfo.Name);
}
}
}
protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}
Usage:
var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new IgnoreJsonPropertyResolver<PlanViewModel>();
var model = new PlanViewModel() {Amount = 100};
var strModel = JsonConvert.SerializeObject(model,settings);
Model:
public class PlanViewModel
{
/// <summary>
/// The customer is charged an amount over an interval for the subscription.
/// </summary>
[JsonProperty(PropertyName = "RecurringPrice")]
public double Amount { get; set; }
/// <summary>
/// Indicates the number of intervals between each billing. If interval=2, the customer would be billed every two
/// months or years depending on the value for interval_unit.
/// </summary>
public int Interval { get; set; } = 1;
/// <summary>
/// Number of free trial days that can be granted when a customer is subscribed to this plan.
/// </summary>
public int TrialPeriod { get; set; } = 30;
/// <summary>
/// This indicates a one-time fee charged upfront while creating a subscription for this plan.
/// </summary>
[JsonProperty(PropertyName = "SetupFee")]
public double SetupAmount { get; set; } = 0;
/// <summary>
/// String representing the type id, usually a lookup value, for the record.
/// </summary>
[JsonProperty(PropertyName = "TypeId")]
public string Type { get; set; }
/// <summary>
/// Billing Frequency
/// </summary>
[JsonProperty(PropertyName = "BillingFrequency")]
public string Period { get; set; }
/// <summary>
/// String representing the type id, usually a lookup value, for the record.
/// </summary>
[JsonProperty(PropertyName = "PlanUseType")]
public string Purpose { get; set; }
}
Expanding Rentering.com's answer, in scenarios where a whole graph of many types is to be taken care of, and you're looking for a strongly typed solution, this class can help, see usage (fluent) below. It operates as either a black-list or white-list per type. A type cannot be both (Gist - also contains global ignore list).
public class PropertyFilterResolver : DefaultContractResolver
{
const string _Err = "A type can be either in the include list or the ignore list.";
Dictionary<Type, IEnumerable<string>> _IgnorePropertiesMap = new Dictionary<Type, IEnumerable<string>>();
Dictionary<Type, IEnumerable<string>> _IncludePropertiesMap = new Dictionary<Type, IEnumerable<string>>();
public PropertyFilterResolver SetIgnoredProperties<T>(params Expression<Func<T, object>>[] propertyAccessors)
{
if (propertyAccessors == null) return this;
if (_IncludePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err);
var properties = propertyAccessors.Select(GetPropertyName);
_IgnorePropertiesMap[typeof(T)] = properties.ToArray();
return this;
}
public PropertyFilterResolver SetIncludedProperties<T>(params Expression<Func<T, object>>[] propertyAccessors)
{
if (propertyAccessors == null)
return this;
if (_IgnorePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err);
var properties = propertyAccessors.Select(GetPropertyName);
_IncludePropertiesMap[typeof(T)] = properties.ToArray();
return this;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
var isIgnoreList = _IgnorePropertiesMap.TryGetValue(type, out IEnumerable<string> map);
if (!isIgnoreList && !_IncludePropertiesMap.TryGetValue(type, out map))
return properties;
Func<JsonProperty, bool> predicate = jp => map.Contains(jp.PropertyName) == !isIgnoreList;
return properties.Where(predicate).ToArray();
}
string GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
if (!(propertyLambda.Body is MemberExpression member))
throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property.");
if (!(member.Member is PropertyInfo propInfo))
throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property.");
var type = typeof(TSource);
if (!type.GetTypeInfo().IsAssignableFrom(propInfo.DeclaringType.GetTypeInfo()))
throw new ArgumentException($"Expresion '{propertyLambda}' refers to a property that is not from type '{type}'.");
return propInfo.Name;
}
}
Usage:
var resolver = new PropertyFilterResolver()
.SetIncludedProperties<User>(
u => u.Id,
u => u.UnitId)
.SetIgnoredProperties<Person>(
r => r.Responders)
.SetIncludedProperties<Blog>(
b => b.Id)
.Ignore(nameof(IChangeTracking.IsChanged)); //see gist
I am using JsonProperty attributes when serializing but ignoring them when deserializing using this ContractResolver:
public class IgnoreJsonPropertyContractResolver: DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
foreach (var p in properties) { p.PropertyName = p.UnderlyingName; }
return properties;
}
}
The ContractResolver just sets every property back to the class property name (simplified from Shimmy's solution). Usage:
var airplane= JsonConvert.DeserializeObject<Airplane>(json,
new JsonSerializerSettings { ContractResolver = new IgnoreJsonPropertyContractResolver() });
Also if you want to ignore something use this
[JsonIgnore]
public int Id { get; set; }
[JsonProperty("id")]
Public string real_id { get; set; }
I want to serialize a simple object to JSON:
public class JsonTreeNode
{
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "isFolder")]
public bool IsFolder { get; set; }
[DataMember(Name = "key")]
public string Key { get; set; }
[DataMember(Name = "children")]
public IEnumerable<JsonTreeNode> Children { get; set; }
[DataMember(Name = "select")]
public bool SelectedOnInit { get; set; }
}
But whenever I do it:
return Json(tree, JsonRequestBehavior.AllowGet);
The property names are not as specified in the [DataMember] section, but similar to the ones defined directly in the class e.g. in the case of SelectOnInit it is not select but SelectOnInit.
What am I doing wrong?
I solved the problem by using the technique provided in the answer in this question:
ASP.NET MVC: Controlling serialization of property names with JsonResult
Here is the class I made:
/// <summary>
/// Similiar to <see cref="JsonResult"/>, with
/// the exception that the <see cref="DataContract"/> attributes are
/// respected.
/// </summary>
/// <remarks>
/// Based on the excellent stackoverflow answer:
/// https://stackoverflow.com/a/263416/1039947
/// </remarks>
public class JsonDataContractActionResult : ActionResult
{
/// <summary>
/// Initializes a new instance of the class.
/// </summary>
/// <param name="data">Data to parse.</param>
public JsonDataContractActionResult(Object data)
{
Data = data;
}
/// <summary>
/// Gets or sets the data.
/// </summary>
public Object Data { get; private set; }
/// <summary>
/// Enables processing of the result of an action method by a
/// custom type that inherits from the ActionResult class.
/// </summary>
/// <param name="context">The controller context.</param>
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var serializer = new DataContractJsonSerializer(Data.GetType());
string output;
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, Data);
output = Encoding.UTF8.GetString(ms.ToArray());
}
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.Write(output);
}
}
Usage:
public ActionResult TestFunction()
{
var testObject = new TestClass();
return new JsonDataContractActionResult(testObject);
}
I also had to modify the initial class:
// -- The DataContract property was added --
[DataContract]
public class JsonTreeNode
{
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "isFolder")]
public bool IsFolder { get; set; }
[DataMember(Name = "key")]
public string Key { get; set; }
[DataMember(Name = "children")]
public IEnumerable<JsonTreeNode> Children { get; set; }
[DataMember(Name = "select")]
public bool SelectedOnInit { get; set; }
}
This is a solution that uses newtonsoft Json.net (for performance concerned)
I've found part of the solution here and on SO
public class JsonNetResult : ActionResult
{
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
public object Data { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult(object data, Formatting formatting)
: this(data)
{
Formatting = formatting;
}
public JsonNetResult(object data):this()
{
Data = data;
}
public JsonNetResult()
{
Formatting = Formatting.None;
SerializerSettings = new JsonSerializerSettings();
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data == null) return;
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
So that in my controller, I can do that
return new JsonNetResult(result);
In my model, I can now have:
[JsonProperty(PropertyName = "n")]
public string Name { get; set; }
Note that now, you have to set the JsonPropertyAttribute to every property you want to serialize.
Is there anyway simple ways to add a property to Linq to Sql generated entity to reference its DataContext?
For example:
var myContext = new DataContext();
var product = context.Products.Where(p => p.Id == productId).SingleOrDefault();
and product entity has a property called "Context" (product.Context) that has a reference to the myContext, datacontext.
I know how to customize generated entities. My question is how to customize (i think DataContext) to set 'Context' property of each instance that it creates to itself.
I'm not sure I'm doing the right thing or not. I want to write a business encapsulation model that has best performance with less code.
As i googled around I have find out that the DataContext object is very lightweight and there for I thought it would be a good way to add an instance of DataContext to each object. This will reduce the need to attach, detached objects again to a new instance of datacontext every time I want to update or delete them.
If you have any other solution I will really appreciate it.
Thanks
Is there a simple way to add a property to Linq to Sql generated entity to reference its DataContext?
There is no simple way to achieve this.
In doing this, you defeat part of the purpose of LINQ-to-SQL. One of the purposes is to allow to you work with the objects that you have, and not have to change your design based on database considerations.
In attaching the DataContext to the database, you are coupling your representation in code with the means to persist it, which is generally a bad design idea.
If you feel you must do this though, you can always derive from the class and then implement an interface on that class which exposes the DataContext.
I recommend implementing the interface, since you can't indicate a base class to the LINQ-to-SQL designer, and you want to be able for all of your entities to have a shared implementation.
See here: Determine the source DataContext for a Linq to Sql query
I asked more or less the same question. You can get the context from the IQueryable that a linq to sql query returns, but not from the entity itself as far as I know.
Actually, I agree to casperOne. If you really have to need this, I remembered that the classes that linq-to-sql generates are partial. So you can write a partial class to any class you want and add extended functionalities to it.
Pass the data context as a ref parameter to a custom method on your partial Product object:
public partial class Product
{
public string GetSomethingElse(ref DataContext dbase)
{
return dbase.OtherTableWhatever.Count.ToString(); // whatever
}
}
Inside your aspx.cs:
var context = new DataContext();
var product = context.Products.SingleOrDefault(x => x.id == 1);
var s = product.GetSomethingElse(ref context);
Here is a custom wrapper I made for System.Data.Linq. It contains a find method, so instead of your code:
var myContext = new DataContext();
var product = context.Products.Where(p => p.Id == productId).SingleOrDefault();
you can do this
var myContext = new DataContext();
var product = context.Products.Find(productId); //(assuming productId is your primary key)
You can grab the code below and do any custom modifications you wish to set product.Context, but this is an example of modifying the DataContext.
I also made save and delete methods. You'll notice I go out a regrab the record even though it is being passed in. I do this because the record might get detached from the context and not update. If anyone would like the full code I can post the github link.
public abstract class DbContext : IDisposable
{
#region Properties
private string _connectionString { get; set; }
private DataContext _context { get; set; }
#endregion
#region Constructor
public DbContext(string connectionString)
{
_connectionString = connectionString;
_context = new DataContext(_connectionString);
Initialized(_context);
}
public DbContext(string server, string database, string userID, string password)
{
_connectionString = string.Format(
"Server={0};Database={1};User Id={2};Password={3};MultipleActiveResultSets=true",
server,
database,
userID,
password);
_context = new DataContext(_connectionString);
Initialized(_context);
}
#endregion
#region Methods
/// <summary>
/// Is used to get the contents of a Sql Server Table.
/// </summary>
/// <typeparam name="TEntity">Type</typeparam>
/// <returns>Table</returns>
public Table<TEntity> GetTable<TEntity, TPKType>()
where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
where TPKType : struct
{
return _context.GetTable<TEntity>();
}
/// <summary>
/// Is used to get the contents of a Sql Server Table.
/// </summary>
/// <typeparam name="TEntity">Type</typeparam>
/// <returns>Table</returns>
public Table<TEntity> GetTable<TEntity>()
where TEntity : DbTableEquatable<IDbTableEquatable<long>>
{
return GetTable<TEntity, long>();
}
protected virtual void Initialized(DataContext context) { }
/// <summary>
/// Saves the changes to the database. In order to save the table must inherit from DbTableEquatable
/// and be a type of IDbTableEquatable and the Primary Key Type must be a C# Structure
/// </summary>
/// <typeparam name="TEntity">Record Type</typeparam>
/// <typeparam name="TPKType">Primary Key Type</typeparam>
/// <param name="entity">Record</param>
public virtual void SaveChanges<TEntity, TPKType>(TEntity entity)
where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
where TPKType : struct
{
var changedList = _context.GetTable<TEntity>();
var ID = entity.GetType().GetProperty("ID").GetValue(entity);
_preprocessSave<TEntity, TPKType>(entity);
// Save changes
if (Convert.ToInt64(ID) == 0)
{
// Insert
// If No ID we need to insert on submit
_context.GetTable<TEntity>().InsertOnSubmit((TEntity)entity);
_context.SubmitChanges();
}
else
{
// Update
var item = changedList.Where(w => w.Equals(entity)).FirstOrDefault();
ReflectionManager.SetValuesWithSkip(entity, item, "ID");
_context.SubmitChanges();
}
Refresh();
}
/// <summary>
/// Saves the changes to the database. In order to save the Table the Record is from must inherit from DbTableEquatable
/// and be a type of IDbTableEquatable and the Primary Key Type must be a C# Structure
/// </summary>
/// <typeparam name="TEntity">Record Type</typeparam>
/// <param name="entity">Record</param>
public virtual void SaveChanges<TEntity>(TEntity entity)
where TEntity : DbTableEquatable<IDbTableEquatable<long>>
{
SaveChanges<TEntity, long>(entity);
}
/// <summary>
/// Saves any non committed changes to the database
/// </summary>
public void SaveChanges()
{
_context.SubmitChanges();
Refresh();
}
/// <summary>
/// Marks the record as delete and will be deleted when saved
/// </summary>
/// <typeparam name="TEntity">Record Type</typeparam>
/// <typeparam name="TPKType">Primary Key Type</typeparam>
/// <param name="entity">Record</param>
public virtual void DeleteOnSave<TEntity, TPKType>(TEntity entity)
where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
where TPKType : struct
{
var item = _context.GetTable<TEntity>().Where(w => w.Equals(entity)).FirstOrDefault();
_context.GetTable<TEntity>().DeleteOnSubmit((TEntity)item);
}
/// <summary>
/// Marks the record as delete and will be deleted when saved
/// </summary>
/// <typeparam name="TEntity">Record Type</typeparam>
/// <param name="entity">Record</param>
public virtual void DeleteOnSave<TEntity>(TEntity entity)
where TEntity : DbTableEquatable<IDbTableEquatable<long>>
{
DeleteOnSave<TEntity, long>(entity);
}
protected virtual void _preprocessSave<TEntity, TPKType>(TEntity entity)
where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
where TPKType : struct
{
}
protected virtual void _preprocessSave<TEntity>(TEntity entity)
where TEntity : DbTableEquatable<IDbTableEquatable<long>>
{
_preprocessSave<TEntity, long>(entity);
}
public void Dispose()
{
_connectionString = "";
_context.Dispose();
_context = null;
}
public virtual void Refresh<TEntity>(RefreshMode mode, TEntity entity) where TEntity : class
{
_context.Refresh(RefreshMode.OverwriteCurrentValues, entity);
}
public virtual void Refresh()
{
_context = new DataContext(_connectionString);
}
public virtual void Refresh<TEntity>(RefreshMode mode, params TEntity[] entities) where TEntity : class
{
_context.Refresh(RefreshMode.OverwriteCurrentValues, entities);
}
public virtual void Refresh<TEntity>(RefreshMode mode, IEnumerable<TEntity> entities) where TEntity : class
{
_context.Refresh(RefreshMode.OverwriteCurrentValues, entities);
}
#endregion
}
Extenstions
public static class Extension
{
public static TEntity Find<TEntity, TPKType>(this Table<TEntity> table, TPKType ID, string pkName = "ID")
where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
where TPKType : struct
{
TEntity copy = Activator.CreateInstance<TEntity>();
// set value through reflection
copy.GetType().GetProperty(pkName).SetValue(copy, ID, null);
return (TEntity)table.Where(w => w.Equals(copy)).FirstOrDefault();
}
public static TEntity Find<TEntity>(this Table<TEntity> table, long ID, string pkName = "ID")
where TEntity : DbTableEquatable<IDbTableEquatable<long>>
{
TEntity copy = Activator.CreateInstance<TEntity>();
// set value through reflection
copy.GetType().GetProperty(pkName).SetValue(copy, ID, null);
return (TEntity)table.Where(w => w.Equals(copy)).FirstOrDefault();
}
}
}
Interface/Abstraction
/// <summary>
/// This Class Assumes the type T has a property called ID. MUST be
/// used with IDbEquatable
/// </summary>
/// <typeparam name="T">Class Type</typeparam>
public abstract class DbTableEquatable<T> : IEquatable<T> where T : class
{
public bool Equals(T other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null))
{
return false;
}
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other))
{
return true;
}
return ((dynamic)other).ID == ((dynamic)this).ID;
}
}
/// <summary>
/// Needs to be inherited from in order for Ion.Data.Linq functions to work
/// </summary>
/// <typeparam name="T">Primary Key Type</typeparam>
public interface IDbTableEquatable<T>
{
T ID { get; set; }
}
here is a table implementation
[Table(Name = "Crews")]
public class Crew : DbTableEquatable<IDbTableEquatable<long>>, IDbTableEquatable<long>
{
[Column(IsPrimaryKey = true, DbType = "Bigint NOT NULL IDENTITY", AutoSync = AutoSync.OnInsert, IsDbGenerated = true)]
public long ID { get; set; }
[Column]
public string Alias { get; set; }
[Column]
public string DefaultForeground { get; set; }
[Column]
public string DefaultBackground { get; set; }
[Column]
public string AccountEmailAddress { get; set; }
[Column]
public long? CrewLeaderEmployeeID { get; set; }
[Column]
public string Comments { get; set; }
[Column]
public string Password { get; set; }
[Column]
public string PrivateICSLink { get; set; }
[Column]
public string PrivateXMLLink { get; set; }
}