Update: Updated article here.

Today I wanted to be able to have a table store any type of value as a way to store some settings for an application. The table needed to be able to store basically a name/value pair.

I designed the object using a code-first approach

Initial Idea

publicclassSetting{[Key]publicstringName{get;set;}publicobjectValue{get;set;}publicstringType{get;set;}}

Simple and to the point.

Here is a snippet from my DataContext

publicclassDataContext:DbContext,IDataContext{publicDbSet<Setting>Settings{get;set;}}

To access the data I would simply cast Value to whatever type I expected it to be.

var x =(string)Settings.Single(s => s.Name=="sitename").Value;

Problems

However, with EF and probably Linq (I didn’t test that) the Value was always null after I calledSaveChanges. At first I couldn’t understand why but then it hit me. There’s no direct relationship between object and SQL. So I switched the Value to a byte[]. Here is my new class.

publicclassSetting{[Key]publicstringName{get;set;}publicbyte[]Value{get;set;}publicstringType{get;set;}}

This caused a few problems with the first method since it’s not possible to typecast from a byte[] to a DateTime, int, string…and so on. So I added a few helper methods to my DataContext.

Solution

public T Setting<T>(stringName){//grab the the setting if it exists otherwisevar value =Settings.SingleOrDefault(s => s.Name==Name);//return the default value for typeof(T)if(value ==null)returndefault(T);//If they're trying to cast to a different type we should throw an error//They can to another type conversion after grabbing the valueif(Type!=typeof(T).FullName)thrownewInvalidCastException(string.Format("Unable to cast: {0} to {1}",typeof(T).FullName,Type));//Using the BinaryFormatter, return a typecast valuereturn(T)(newBinaryFormatter().Deserialize(newSystem.IO.MemoryStream(value.Value)));}publicvoidSetting<T>(stringName, T Value){//check for an existing valuevar setting =Settings.SingleOrDefault(s => s.Name==Name);//serialize the new valueSystem.IO.MemoryStream ms =newSystem.IO.MemoryStream();newBinaryFormatter().Serialize(ms,Value);if(setting !=null){//for consistency let's make sure we're assigning the same typeif(Type!=typeof(T).FullName)thrownewInvalidCastException(string.Format("Unable to cast: {0} to {1}",typeof(T).FullName,Type));
setting.Value= ms.ToArray();}else{//add a new value to the database
value =newModels.Setting(){Name=Name,Type=typeof(T).Fullname,Value= ms.ToArray()};Settings.Add(value);}}

Now instead of calling the above cast we can now use the following

var x =DataContext.Setting<string>("sitename");//getDataContext.Setting<string>("sitename","buildstarted.com");//set

Hope this is helpful and inspires someone. Please comment if you have a better method. I’m not too keen on serializing all the time but it’s the best method I’ve come up with so far.

One of the problems with having values stored in byte[] form is lack of searchability of values. However, you’re unlikely to select all settings with values of “true”.

So after working with the Settings table from my previous post a bit, it’s clear to me that creating some extension methods would make working with settings easier. To do this though we have to modify the Model a bit first and rename “Value” to lowercase “value”. The summary xml documentation is there to inform the user there’s an Extension method

publicclassSetting{publicintSettingID{get;set;}publicstringName{get;set;}/// <summary>/// Use the extension methods instead of this value; ex: Value&lt;T&gt;/// <summary>publicbyte[] value {get;set;}publicstringType{get;set;}}

Creating the Extension Method

[Extension]publicstatic T Value<T>(thisSetting setting){if(setting ==null)returndefault(T);if(setting.Type!=typeof(T).FullName)thrownewInvalidCastException(string.Format("Unable to cast: {0} to {1}",typeof(T).FullName,
setting.Type));return(T)(newBinaryFormatter().Deserialize(newSystem.IO.MemoryStream(setting.value)));}[Extension]publicstaticvoidValue<T>(thisSetting setting, T value){if(setting ==null)thrownewArgumentNullException("setting");System.IO.MemoryStream ms =newSystem.IO.MemoryStream();newBinaryFormatter().Serialize(ms, value);if(setting.Type!=typeof(T).FullName)thrownewInvalidCastException(string.Format("Unable to cast: {0} to {1}",typeof(T).FullName,
setting.Type)); setting.value = ms.ToArray();}

Doing this also has the added benefit of making the Generic methods in the DataContext cleaner

public T Setting<T>(stringName){var setting =Settings.SingleOrDefault(s => s.Name==Name);return setting.Value<T>();}publicvoidSetting<T>(stringName, T Value){var setting =Settings.SingleOrDefault(s => s.Name==Name);
setting.Value<T>(Value);}

As you can see the extension methods are very easy to create. This gives us the benefit of accessing the values in a cleaner way

var setting = db.Settings.First();
setting.Value<string>("this is a new value");var theValue = setting.Value<string>();

The generic methods are what make the settings Model powerful and (almost) seamless.

– Ben

http://buildstarted.com/2010/08/09/creating-a-settings-table-that-can-handle-almost-any-type-of-value/

Creating a settings table that can handle almost any type of value的更多相关文章

  1. Fun with dynamicobject dynamic and the settings table

    What came before In my previous post I discussed ways of making the settings table using Generics to ...

  2. webpack 3.8 使用 extract-text-webpack-plugin 3.0 抽取css失败:You may need an appropriate loader to handle this file type.

    webpack 3.8.1 使用 extract-text-webpack-plugin 3.0.2 抽取css时失败,报错: ERROR in ./src/static/style/localTim ...

  3. Column 1 of table 'xxx' cannot be converted from type 'varchar(33)' to type 'varchar(11)'

    mysql主从同步失败.错误日志如下. Column 1 of table 'xxx' cannot be converted from type 'varchar(33)' to type 'var ...

  4. RoR - Creating and Modifying Table and Columns

    自动生成的id 被当作primary key来使用 timestamp method生成 created_at 与 updated_at columns create_table 和 drop_tab ...

  5. vue-cli使用vux时报错处理,“You may need an appropriate loader to handle this file type”

    先说解决方案: 在项目中找到build,找到webpack.base.conf.js 将vux给出的解决方案代码拷贝出来 const vuxLoader = require('vux-loader') ...

  6. “You may need an appropriate loader to handle this file type”

    这里不能为空!!!!!!!!!!!!!!!!!!!!

  7. vue Module parse failed: Unexpected token You may need an appropriate loader to handle this file type

    1.错误截图: 2.错误原因:webpack 原生只支持 js 文件类型,及 es5 的语法 3.解决方法:在webpack.config.js中,增加以下配置 module: { rules: [ ...

  8. centos linux系统日常管理复习 CPU物理数逻辑核数,iftop ,iotop ,sar ,ps,netstat ,一网卡多IP,mii-tool 连接,ethtool速率,一个网卡配置多个IP,mii-tool 连接,ethtool速率 ,crontab备份, 第十八节课

    centos linux系统日常管理复习 物理CPU和每颗CPU的逻辑核数,uptime ,w,vmstat,iftop ,iotop ,sar ,ps,netstat ,一个网卡配置多个IP,mii ...

  9. Linux系统入门命令100条 转

    https://www.howtoforge.com/linux-commands/ 2017-04-27 RiboseYim 睿哥杂货铺 Author : Himanshu Arora 原文:htt ...

随机推荐

  1. php 字符编码转换函数 iconv mb_convert_encoding比较

    在使用PHP处理字符串时,我们经常会碰到字符编码转换的问题,你碰到过iconv转换失败吗? 发现问题时,网上搜了搜,才发现iconv原来有bug ,碰到一些生僻字就会无法转换,当然了配置第二个参数时, ...

  2. const volatile int i

    问题: const volatile int i=10:这行代码有没有问题?如果没有,那 i 到底是什么属性? 回答: 没有问题,例如只读的状态寄存器.它是volatile,因为它可能被意想不到地改变 ...

  3. DataTables列过滤器

    var table = $('#example').DataTable(); table.columns().flatten().each( function ( colIdx ) { // Crea ...

  4. Pausing Coyote HTTP/1.1 on http-8080

    一般情况下我看到8080便认为是端口占用的问题,其实不是,但是在任务管理器中并没有找到javaw.exe,只有javaservice.exe, 只有重启tomcat了,蓝后就好了......

  5. Gson 禁止特殊字符转码

    Map<String,String> map = new HashMap<String,String>(); map.put("url", "&a ...

  6. Android扩展 - 拍照篇(Camera)

    1.调用系统摄像头 1.声明常量和变量 2.按钮点击事件,打开系统摄像头 3.重写onActivityResult事件接收拍照返回 4.生成文件名返回路径 5.保存图片 private static  ...

  7. Js树型控件Dtree使用

    dtree地址:http://destroydrop.com/javascripts/tree/ Key features Unlimited number of levels 无限级 Can be ...

  8. BZOJ2754: [SCOI2012]喵星球上的点名

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 680  Solved: 314[Submit][Sta ...

  9. 减少leftJoin的使用 (转)

    作为开发,你是否经常碰到下面需要转换用户ID成用户名称的情况: 可惜你的这些业务表出于最少冗余设计要求,只有UserId,而没有UserName,这时你不得不破坏你一个类封装一个表的美好想法, 在你的 ...

  10. jQuery中ajax的使用和缓存问题解决 $getjson 与$get都会被IE缓存

    原文地址:http://www.cnblogs.com/fullhouse/archive/2012/01/17/2324842.html 1:GET访问 浏览器 认为 是等幂的就是 一个相同的URL ...