Linq to SQL storage attribute issue - c#

I have an application that gets and stores data to a database using Linq to SQL. I have a field for a phone number. I am trying to store this consistently as only digits and nothing else. To do this, I have two extension methods I've added to strings. ToPhoneFormat() formats the phone digits as the user wants such as "(xxx) xxx-xxxx" or "xxx.xxx.xxxx". ToPhoneStorage() removes all formatting and only saves the digits from the number for use with the database.
Here's a sample of code used with the Linq to SQL:
private string homePhone;
[Column(CanBeNull = true, DbType = "nvarchar(25)", Name = "HOME_PHONE_NUM", Storage = "homePhone")]
[Display(Name = "Home Phone")]
public string HomePhone {
get { return homePhone.ToPhoneFormat(); }
set { homePhone = value.ToPhoneStorage(); }
}
When I submit changes using the DataContext, Linq does in fact call the getter here, and the formatted phone gets sent back to the database. Am I not understanding the Storage attribute properly? Seems like it should work correctly like this.
Of course I can create two fields "PhoneDigits" and "PhoneFormatted" and only provide the column atribute to the "Phone" field. So I know there's a work around. But what does the Storage attribute do if it doesn't do this?

The ColumnAttribute's Storage property tells Linq-to_Sql to use the private field homePhone to get and set values of the property. So the actual getter and setter are bypassed.
You could remove the Storage property assignment. The code doesn't look like a part of a generated dbml, so this won't get overwritten. On the other hand I don't think linq-to-sql will be able to track changes to the property without the regular plumbing code in the setter (SendPropertyChanged etc.). And if you add this code manually it will also be triggered when the object gets materialized from the database, so it will always start its life in a modified state. (That's what's prevented by setting the private member). A rock and a hard place...

Related

C# Google SDK Update or Patch User

Having problem using update User with the google Admin SDK for C#.
https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/update
This method supports patch semantics, meaning you only need to include the fields you wish to update. Fields that are not present in the request will be preserved, and fields set to null will be cleared.
This differs from the Patch as patch won't clear fields that are null but only update fields that have a value.
Problem is that I have to pass a full Google.Apis.Admin.Directory.directory_v1.Data.User class to the function which will contain null of even properties i do not want to clear.
example:
public User UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
{
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(gUser, gUser.Id);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Is there any way of modifying the Body in UpdateRequest before executing it?
Edit:
The UpdateRequest has a ModifyRequest Property that looks like this
I just have no Idea how to use it, any ideas?
public Action<HttpRequestMessage> ModifyRequest { get; set; }
As far as updating things to the concept of Null that is not something that can be done with PATCH. I recommend setting it to an empty string.
You should also not be sending the full user object if thats what you are currently doing. I am going to assume that you have done a users.list to find the user you want to update and change something in that user, say the name. Then you have simply submited the full user object to your method
UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
This wont work as some of the fields you have sent as part of the update/patch are not actually writeable.
What you should do instead would be to create a new user object change what ever it is you want
public User MakeUserAdmin(Google.Apis.Admin.Directory.directory_v1.Data.User gUserId)
{
var updateFields= new Google.Apis.Admin.Directory.directory_v1.Data.User();
change.IsAdmin = true;
change.Addresses = ""; // will set it to empty yes not null but the best you can do with this api.
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(updateFields, gUserId);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Notice how you just need to create a new object and update only the fields you need then send that.
Dont try to update every field, just update the ones that you know have changed. Dont include the id in the object that is not writeable either.

How to check this exact class isn't already in DB with another name? (MongoDB)

Using C# and MongoDb im saving a class similar to the following.
public class Zone
{
public string ZoneName { get; set; }
public List<string> IncludedCountries { get; set; } = new List<string>();
}
This is filled by user and saved in my DB, currently I am checking that the zone name isn't duplicated when inserting. Like so.
if (All().Any(x => x.Name.ToLower() == zone.Name.ToLower())) { throw new System.Exception($"Zone \"{zone.ZoneName}\" is already in database, please edit the zone"); };
But if user currently tries to add the exact same values (So exact same list of included countries) with different name, I wouldn't catch it.
I want to be able to, as dont want to be duplicating same classes in DB (My actual class will have more properties, this is an example). I am aware I can check it the same way im checking for name, but having in mind I have a lot of properties, i'd like to know what the best way is..
Ideally you wouldn't perform a search, then use that to decide whether to add or not. In a collaborative system with potentially multiple users you could find another user in another transaction runs the same code at the same time, and ends up adding the record just after your check, but just before your insert.
It's better, assuming your datastore supports it, to use a uniqueness constraint on some value of the data you're inserting. Here's the docs for Mongo: https://docs.mongodb.com/manual/core/index-unique/
This means the transaction will be failed by the database if you attempt to insert a duplicate. To be fair, there's nothing wrong with doing the "ask-then-tell" as well I suppose, in order to avoid ugly exceptions being shown to users, but if you're able to interrogate the exception details you can probably catch it and show the user some helpful information rather than letting them see an error page.
To support your requirement for "has the same list of things" in this way, I'd suggest creating a SHA256 hash value (here's a link: https://stackoverflow.com/a/6839784/26414) for the list, and storing that as a property in it's own right. Just make sure it's recalculated if the list changes.
One additional thing - technically "class" defines the schema, or shape of a bit of data. When you create an instance of a class at runtime, which has actual values and takes up memory, that's technically an "object". So an "object" is an "instance" of a "class".

How to update all document fields except specified ones in mongodb

I present a simple model:
public class UserDocument
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string DisplayName { get; set; }
public List<string> Friends { get; set; }
}
I am using the latest C# driver which has the ability to replace a document using a C# object which will automatically update all its fields. Problem is I want to update all fields except for the user friends, because it's a field containing the object relations to other documents. Of course I can manually update each field of the ones I want to get updated, which here are just two.
But this example is simple just to make my point. In reality the fields are much more and it would be harder to update each field. That would require a single line for each one to use the Set operator. Also, newly-added fields would have to be supported in the same way as opposed to updating to automatically just works.
Is there a way to achieve that - automatically update all fields with just specifying a list of excluded fields?
There is no way, using the provided builders to have a "blacklist" update which excludes only specific fields.
You can query the old document, copy the old values of these fields to the new instance and then replace it entirely in the database.
You can also generate such an update command by iterating over the fields using reflection.
But the MongoDB driver doesn't offer such a query built in.
I figured out a way to do this with MongoDB using Javascript/NodeJS, but maybe the logic can translate to C#?
I wanted to update all fields without having to actually explicitly state them (all fields except for one, it turned out).
Attempted update of all document fields:
await examCollection.findOneAndUpdate(
{_id: new ObjectID(this.examId)},
{$set: this.data}
)
...except, this.data happened to have _id in it as well, which I didn't want to update. (In fact, it gave me an error, because _id is immutable.)
So, for my workaround, I ended up "deleting" all fields on the object that I didn't want to update (i.e. _id).
Successful update of all non-specified document fields:
// (1) specify fields that I don't want updated (aka get rid of them from object) (similar option in C#?)
delete this.data._id
//delete this.data.anotherField
//delete this.data.anotherField2
//delete this.data.anotherField3
// (2) update MongoDB document
await examCollection.findOneAndUpdate(
{_id: new ObjectID(this.examId)},
{$set: this.data}
)
This was much easier than explicitly stating all the fields I did want to update, because there were A LOT, and they could potentially change in the future (new fields added, fields deleted, etc.).
Hopefully this strategy can help!
Note: In reality, I did my "field specifying" earlier in another file, rather than immediately before updating like it shows in the example, but same effect.

Updating a property using the Content Service api in Umbraco 6.x

I've created a custom user control for the back-end of my Umbraco site that allows administrators to quickly update certain fields on nodes without having to navigate through the content tree.
So far my code is working as expected: I can update simple true/false properties without a problem. However now I'm trying to update a property that's of a custom data type and I'm running into difficulties.
The data type itself is just a simple drop down that lists a series of availability statuses ie. Available, Unavailable, Sold and Reserved. The datatype is storing the text values.
Here's the code I have that allows me to update my true/false properties:
public void ChangeInteractiveStatus(string nodeId, bool chkValue)
{
var cs = ApplicationContext.Current.Services.ContentService;
var apartment = cs.GetById(Convert.ToInt32(nodeId));
apartment.SetValue("displayOnInteractive", chkValue);
cs.SaveAndPublish(apartment);
}
This works absolutely fine as the data type of this property is a regular true/false data type.
Here's the code I'm using to change the value of my custom dropdownlist data type:
public void ChangeAvailabilityStatus(string nodeId, string status)
{
var cs = ApplicationContext.Current.Services.ContentService;
var apartment = cs.GetById(Convert.ToInt32(nodeId));
apartment.SetValue("status", status);
cs.SaveAndPublish(apartment);
}
As you can see there's very little difference and yet this code isn't working.
In order to check what was happening when I was updating the properties with the above code, I checked the umbraco.config file only to find that the property in question was displaying as follows:
<status><![CDATA[]]></status>
However when I change the value in the content tree (without using my admin control) the value gets saved properly as:
<status><![CDATA[Sold]]></status>
So for whatever reason, when I try to update the value it's being rejected and I can't work out why.
FYI I tried entering the value as:
"<![CDATA[" + status + "]]>"
Yet that made no difference.
Does anyone know how I can fix this? How can I get the property to update correctly?
Thanks
Okay I've figured out what the problem was. It seems the values were being stored as name-value pairs, so the actual value getting stored in the database was an integer. Once I updated the code to insert the integer id it all worked as expected! Hooray.

Managing Dynamic Website Settings Persisted in a Database

I am trying to create something to hold global site-wide settings in our ASP.NET website - things such as site name, google analytics account number, facebook url etc... The site can have multiple ‘brands’ or sub-sites associated with it, hence the sitguid column, we would also like to have the option to put them into groups, hence the group column – e.g. TEST and PRODUCTION (set via web.config appsetting).
I do not want any of the KEY’s to be hardcoded anywhere, but I would like to be able to reference them as simply as possible in code, e.g. SiteSetting.getSetting(“SiteName”) (these may be used in templates (masterpages and such) that more junior devs will create)
I would also like to be able to administer the existing settings in our admin console and to be able to create new settings.
The datatype column is for the edit form so that the correct input element can be used, e.g. checkbox for bit types, text box for varchar etc...
SiteSettings database table currently:
[sts_sitGuid] [uniqueidentifier] NOT NULL, -- tells us which site the setting is for
[sts_group] [nvarchar](50) NOT NULL, -- used to group settings e.g. test/live
[sts_name] [nvarchar](max) NULL, -- the display name of the setting, for edit forms
[sts_alias] [nvarchar](50) NOT NULL, -- the name for the setting
[sts_value] [nvarchar](max) NOT NULL, -- the settings value
[sts_dataType] [nvarchar](50) NULL, -- indicates the control to render on edit form
[sts_ord] [tinyint] NULL, -- The order they will appear in on the admin form
I am part way through having this working at the moment, but I am not happy with the way I have done it and would like any advice people here have that might help find the ‘right’ solution! I'm sure people have done this before me. (I would share what I have so far, but do not want to skew the answers in any particular way) All i'm looking for is an overview of how this might be best done, not looking for anyone to write it for me ;)
I’ve done quite a bit of searching both here and Google and have not really found what I’m looking for, especially the ability to add new setting ‘definitions’ as well as editing the settings that exist.
The system runs on ASP.NET using webforms, it's all written in c# and uses MSSQL 2008.
As always, any help is very much appreciated!
EDIT: To clarify I am going to explain what I have built so far. I am dead set on storing all of this in SQL as we don't want web.config or other xml files or another database floating around since it'll give us more to do when we rollout the app to other customers.
So far I have a SiteSettings class, this has a method GetSetting which i can call with GetSetting("SettingAlias") to get the value for "SettingAlias" in the DB. This class's constructor fetches all the settings for the current site from the database and stores those in a dictionary, GetSetting reads from that dictionary. All of that part I am happy with so far.
The part I am struggling with is generating the edit form. The previous version of this used a webservice to get/set the settings and I am trying to continue using something similar to save work, but they were all defined in the code, such as GoogleAnalyticsID, Sitename etc... and each had a column in the database, the change I am making is to store these settings as ROWS instead (since then it's easier to add more, no need to change the schema & all of the sitesettings class) Currently my SiteSettings class has a SiteSettingsEditForm method which grabs all the info from the db, creates a bunch of controls for the form elements, puts that in a temporary page and executes that, then passes the HTML generated to our management system via ajax. This feels wrong and is a bit clunky, and is the reason for posting it here, I am having trouble figuring out how to save this stuff back via the webservice, but more importantly generating a bunch of HTML by executing a page containing a load of form controls just feels like the wrong way to do it.
So in summary I (think i) want to write a class to be able to cache & read a handful of rows from a database table, and also give me an edit form (or give data to something else to generate the form) that is dynamic based on the contents of the same database table (e.g. where my type column is 'bit' I want a checkbox, where it is 'text' I want a text input)
Sometimes this kind of problem is easier to visualize if you start off with the data model. If you want a setting per row, then two tables would probably be the best way to store this:
Site:
SiteId SiteKey SiteName
1 XYGZ4345 Client Site 1
2 AZT43752 Client Site 2
This would define the list of sites you have config for. I'd use a SiteKey as you'd put this in your web.config and it's better to abstract this away into a random string or GUID (to make it harder to accidentally load someone else's config), the client can change their name and you don't get confused in the future as you didn't use their old name as a key etc etc.
The config table itself is also simple, if we treat every setting as a string:
SiteSetting:
SettingId SiteId SettingName SettingValue
1 1 Brand KrustyBrand
2 1 GoogleId MSFTSUX0R
3 2 Brand ConfigMasters(TM)
You can then load all the config quite simply:
SELECT * FROM SiteSetting INNER JOIN Site ON (SiteSetting.SiteId = Site.SiteId) WHERE Site.SiteKey = 'XYGZ4345'
Now we have a list of key value pairs you could then store in a class like:
public class SiteSetting
{
public Site Site {
get; set; //Site would just be a simple class consisiting of Id, Key and Name to match the database table
}
protected Dictionary<String, String> Settings { get; set; } //Simple key value pairs
}
So this is a very simple solution. However, we can take it further - things to consider:
1) Can we add an environment to this somewhere?
We could either add a site per environment
OR
Add an environment to the SiteSetting table. The advantage of this is that you could define enironment = 'ALL' to avoid duplication.
OR
The database the configuration is loaded from defines the environment; so you change the config connection string in the app config. Of course, to connect to a different environment you have to change app.config, but you would potentially have to do that anyway to change the client key and/or environment.
2) Add the concept of user defineable settings - some settings you are going to want to change, some you are going to want to lock. A bit column containing "UserDefinable" would allow you to sort this out
3) Typing of settings.
This is slightly more difficult. You might have something like:
PropertyId PropertyName PropertyType Format UserDefined
1 Brand String NULL 1
2 DatePresentation DateTime "yyyy-MM-dd" 1
The Settings table then only defines a value, and a PropertyId. The advantage of this is that you can then start to increase the information about each setting you are storing, and reuse this information as the design is more normalized. The Settings class then changes like so:
public List<PropertyValue> { get; set; } //replacing the dictionary
PropertyValue then looks something like:
public class PropertyValue
{
int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public string PVType { get; set; } //Could be an enum
public string DisplayFormat { get; set;
private string _RawValue;
public string Value{
get{
switch(PVType){
case "DateTime":
return Convert.ToDateTime(_RawValue).ToString(DisplayFormat);
break;
case "Double":
return Convert.ToDouble(_RawValue).ToString(DisplayFormat);
break;
default:
return _RawValue;
}
}
set{
_RawValue = value;
}
}
}
Things like the Value method need to be improved to support robust error handling (you could also investigate using Convert.ChangeType to simplify the switch block)
This topic is as simple or as complicated as you choose to make it ;-)
Editing
As regards maintaining them; a very simple GUI would allow the user to see all of their properties in a tabular format. You might consider having rows where UserDefinable = 0 as readonly, otherwise the user can edit and add rows. You'd need to validate, especially for duplicate Setting Names for example.
The easiest way to do this is to use the DataGrid; a simple mockup might look something like this:
And a more sophisticated approach might look something like this
Generating the form is therefore as simple as databinding a collection of PropertyValue objects to your chosen grid solution.
As you probably found, there are a variety of ways that you can do this, ranging from Microsoft-recommended to 100% roll-your-own. You're currently on the roll-your-own end of the spectrum, which I think is usually better anyway.
Anyway, basically what you're looking for is a StateBag. Something loosely typed and highly configurable, which doesn't really lend itself very well to an RDBMS, but if you already have the SQL Server in place, it's probably going to be easiest to just use that.
Option 1: Redis
However, another option is to run something like Redis for site configurations. You can store it as a collection of key/value pairs in a Redis object, pull it in a JSON object, and then either convert that to a Hashtable, where lookups will be very fast, or some other hashable collection. A simple wrapper class around the collection would suffice.
Redis is very light and in your case wouldn't require a lot of configuration or maintenance.
Option 2: SQL Server
The way you've mentioned is actually a pretty good way of doing it, but rather than query the database every time, put a strongly typed collection or Hashtable in the cache and let it expire every few hours.
If you go with essentially what you have now, you could store it like this:
Setting
SettingId Int PK,
Key NVarchar(50),
Name NVarchar(50),
Description NVarchar(1000),
Type NVarchar(50),
Priority Int
Configuration
SiteId Int,
SettingId Int FK(Setting),
SettingValue NVarchar(1000)
Don't store things like live/test/dev in the database. You need to have completely separate databases and servers to distinguish between live/test/dev/stage/QA etc.
im currenctly doing this by creating a class which have all the settings as propertiese like
class Setting
{
GUID siteGuid{get; set;}
//other settings
}
then i created a static class SettingManager like this
public static class SettingManager
{
private ConcurrentDictionary<GUID,Setting> settings= new ConcurrentDictionary<GUID,Setting>;
GetSetting(Guid siteGUID)
{
settings.TryGet(siteGuid);
Lastrefreshed = DateTime.Now;
//other code
}
Private DateTime LastRefreshedOn = DateTime.Now;
public void PopulateSetingsDic()
{
//populate the settings dictionary by getting the values from the database
}
}
now anywhere in your code just include the namespace and use the settings.
u can populate the settings once or on every interval in application_start using lastRefreshedOn variable
it will be fast because u have all the settings inside the memory.
also if u want that the u should be able to add the settings dynamically then u can use an ExpandoObject and add settings dynamically using the column names from the database or just a mapping
then ull be able to use the settings by casting the settings ExpandoObject to IDictionary<string,object> here string can be the string converted GUID
Edit:- http://zippedtech.blogspot.in/2012/04/dynaminism-in-net-40.html check the link.. i have added a new post for solution to problems like this.
I would use xml, make a class that can take xpath as your "key"
Ex.
MySett.get("//level1/mysetting")
or even
MySett.get("//mysetting")
where each one can return a collection, just the first one, or what ever you want.
You could even overload.
I like xml because of it's great flexability, and to reduce code elsewher, just write a class.
Downside, You need to load your document at application startup and save at shutdown.
Here is an example class in vb code. (c code would still be very similar, I just used vb because it was up at thetime
Imports System.Xml
Public Class XSett
Public xml As XmlDocument
Public Overloads Function gett(ByVal xp As String)
Return CType(xml.SelectSingleNode(xp), XmlElement).InnerXml
'by using inner xml, you can have either text setting
'or more markup that you might need for another function
'your choice. you could even cast it into another instance
'of this class
End Function
Public Overloads Function gett(ByVal xp As String, ByVal sel As Integer)
Return CType(xml.SelectNodes(xp)(sel), XmlElement).InnerXml
'here, you can have multiple and choose the one you want
End Function
Public Overloads Sub gett(ByVal xp As String, ByRef col As Collection)
Dim i As Integer
Dim nds = xml.SelectNodes(xp)
For i = 0 To nds.Count - 1
col.Add(CType(nds(i), XmlElement).InnerXml)
Next
'Creted an entire collection of elemens.
'i used vb's "collection" object, but any collection would do
End Sub
Public Overloads Sub sett(ByVal ap As String, ByVal name As String, ByVal data As String)
'assume add here.
'ap asks for existing parent element. eg: //guids
'name ask for name of setting element
Dim ts = xml.CreateElement(name)
ts.InnerXml = data
If ap = "" Then 'we assume document element
xml.DocumentElement.AppendChild(ts)
Else
Dim p = CType(xml.SelectSingleNode(ap), XmlElement)
p.AppendChild(ts)
End If
End Sub
Public Overloads Sub sett(ByVal xp As String, ByVal sel As Integer, ByVal data As String)
'just change existing setting
CType(xml.SelectNodes(xp)(sel), XmlElement).InnerXml = data
End Sub
'naturally you can expand infinitely if needed
End Class
If I understand your question correctly you are looking for a centralized configuration framework. For configuration & server management I would normally recommend Chef or Puppet however for ASP.NET I did some quick googling and it seems like the WCF based Configuration Service might do the trick for you. The document I linked to is a step by step tutorial for the configuration service used in the .NET StockTrader 5 Sample Application.

Categories

Resources