I need to export data from SQL Server when a specific column is updated and wonder if there is some recommended way to do this?
I have a table with an column 'Activated', when this value is changed to true an export should be trigged.
I soppose I need a trigger that reacts on changes in the 'Activated'. And my two options at present is to call the webservice directly from the trigger or let the trigger insert data in a table that my one service reads from and calls the extern service.
Is any of this ideas preferable or is there any other better solution?
you should check out the SQL Server Service Broker - it can be used to trigger external actions on changes to the data.
one implementation (which I have not used) can be found here: http://lab.arc90.com/2009/02/05/sqlwatcher-ad-hoc-database-change-monitoring/
If you have infrequent changes in data (for example classified values), you can use Query Notifications + SQLDependencies class. Behaind the scene its also uses Service Broker #paul mentioned.
For example, you can have table:
CREATE TABLE dbo.MyTable
(
MyTableID INT not null PRIMARY KEY IDENTITY,
SomeText nvarchar(50)
)
And SQL code (user rights are discussed here):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
SqlDependency.Start("server=<MyServer>;database=<MyDB>;User ID=<user>;Password=<pwd>;Integrated Security=false;");
Console.WriteLine("Started..");
get_msg();
Console.ReadLine();
SqlDependency.Stop("server=<MyServer>;database=<MyDB>;User ID=<user>;Password=<pwd>;Integrated Security=false;");
}
private static void get_msg()
{
using (SqlConnection con =
new SqlConnection("server=<MyServer>;database=<MyDB>;User ID=<user>;Password=<pwd>;Integrated Security=false;"))
{
SqlCommand com = new SqlCommand("SELECT MyTableID, SomeText FROM dbo.MyTable ", con);
SqlDependency dependency = new SqlDependency(com);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
con.Open();
com.ExecuteNonQuery();
}
}
static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
Console.WriteLine("dependency Info = {0}, time: {1}",e.Info, DateTime.Now);
get_msg();
}
}
}
Related
I'm trying to write a Azure Webjob to insert a record into a Azure SQL.
Here is my code:
using System;
using System.Configuration;
using System.Data.SqlClient;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("runing... "+ DateTime.Now.ToString());
SqlConnection con = new SqlConnection();
con.ConnectionString = ConfigurationManager.ConnectionStrings["AzureDB"].ConnectionString;
con.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO [dbo].[myTest] ([CreateTime]) VALUES (GETDATE ( ))", con);
cmd.ExecuteNonQuery();
con.Close();
}
}
}
At the beginning, I just had a Console.WriteLine code which worked fine but just after adding the codes related to reading the connectionstring and data it failed.
Do we need to upload the ddls?
Azure WebApps do not yet support .NET version 4.6.1. That framework version is not yet installed on the hosting VMs. It should be supported in the next couple months, but isn't yet. In the mean time, if you change your WebJob to target 4.6 it will work.
I am a newbie at JSON programming. Most of my experience is in C# and some in XML and Javascript. So I am a bit lost. I will attempt to be as specific as possible.
I have written a windows console application that runs via the task scheduler. Basically the windows application is supposed to take the API from a site that is managed by an outside company but the information is owned by my company and put the information within a SQL table. The API is pretty standard and written in JSON.
I am successful in parsing the JSON language and (for example) displaying it in a command prompt but I need to be able to parse the language and place it into an SQL table. I have read up on SQL injection attacks and I feel fairly confident that we have covered our bases here. So the problem lies in the fact that it does not update the table when the application is run via the scheduler or without the scheduler.
I have included a little bit of the JSON language below along with the language for my console application.
{"date":"2015-09-24","data":[{"cid":"17","rank":1},{"cid":"26","rank":1},{"cid":"80","rank":1},{"cid":"30","rank":1},{"cid":"90","rank":1},{"cid":"62","rank":1},{"cid":"147","rank":1},{"cid":"28","rank":1}"s":1,"e":null}
using System;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using System.Threading.Tasks;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonApiClient
{
class Program
{
static void Main(string[] args)
{
ExecuteRiskSearch();
Console.ReadLine();
}
static void ExecuteRiskSearch()
{
string url = "https://localhost/api/getWatchList/";
string json = new WebClient().DownloadString(url);
JObject results = JObject.Parse(json);
foreach (var result in results)
{
string cid = (string)results["CID"];
JToken rank = results["rank"];
string risk = "";
if (rank is JValue)
{
risk = (string)rank;
}
else if (rank is JArray)
{
risk = (string)((JArray)rank).First;
}
else
{
SqlConnection connection = null;
SqlCommand command = null;
try
{
connection = new SqlConnection("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=apiData;Data Source=serverName;");
command = new SqlCommand("UPDATE apiData.dbo.API SET [Category] WHERE CID=CID", connection);
connection.Open();
int numrows = command.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
command.Dispose();
connection.Dispose();
}
}
}
}
}
}
What am I missing to make the JSON data update my SQL table? I have scoured Google search results and I haven't found much information. Any help would be so greatly appreciated.
For the need to foreach with the correct part of the JSON object, what I mean is very simply that your variable results includes the entire JSON object, from the "date" through the "e". You need to start with the "data" object and iterate through its array or your string cid will error out on assignment, as it will be attempting to assign an array to a single value. The same goes for your JToken rank. I believe it should be this:
foreach(datum in results["data"])
{
string cid = datum["cid"];
JToken rank = datum["rank"];
/* ... */
}
In addition, your set command isn't doing anything. You need to use SET columName = " + newValue + " WHERE CID == " + cid to actually affect a change, where columnName is the column you wish to alter and newValue is your C# variable carrying the desired replacement.
It's also a best practice to include a change to an updated date field when updating via an automated process, if there is one present. Generally the convention is to have a created date and an updated date for each row in a table.
I hope this at least points you in the right direction.
-C§
As an alternative, you can send entire text to Sql Server and load it there.
Sql Server 2016 will enable you to store JSON using single command - OPENJSON. In the older versions you can use existing CLR/JSON libraries such as Json4Sql or JsonSelect.
I am trying to use Dapper for our complex queries to remove any lost overhead that was previously existing with NH.
I have the following query (note this has been considerably shrunk):
SELECT DISTINCT *
FROM tasks t
WHERE t.initials = #UserInits
Which is called via our repository as so:
taskRepo.RawExec<TaskListItemDTO>(Query,new {UserInits = "SAS"})
Our implementation of DapperExec consist as follows:
public IEnumerable<T> RawExec<T>(string SQL, object param)
{
return _session.Connection.Query<T>(SQL,param);
}
But Dapper doesn't appear to be adding the parameters to the query, and as a result, we are getting syntax errors.
Incase it helps, we are connecting over ODBC to Informix.
Thanks
Update Code Sample:
Sorry it took so long, been very busy with work! Below is a sample for MS SQL (2008) Server that should simple query the sys.all_objects (systables?) with a param value of 1 or 0 - but in this sample, as ODBC does not use named params, this won't work.
using Dapper;
using DapperSQL;
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
namespace DapperTests
{
public class SQLEx
{
private OdbcConnection GetConnection()
{
var cnn = new OdbcConnection("DSN=ODBCSOURCE");
cnn.Open();
// wrap the connection with a profiling connection that tracks timings
return cnn;
}
public IEnumerable<object> DapperTest()
{
using (OdbcConnection conn = GetConnection())
{
return conn.Query("SELECT * FROM sys.all_objects where is_ms_shipped = ?", new { is_ms_shipped = 1 });
}
}
}
I know this is old post, just use SP instead of query, please check this link Dapper using ODBC store procedure Input parm, this using sybase odbc Sp, all odbc use same technique, I wish it works in Informix.
Based on this link it looks like I can get date inserted / date modified information "for free" (without the need for triggers etc.) using Sql Server 2008 by simply enabling Change Tracking. I am using Entity Framework to access the data. My question is, how do I access date modified / date inserted information for the database records via Entity Framework and LINQ?
I'm using VS2008 so I don't have the new EF v4 stuff yet (but if it can be done in the new EF please let me know).
Thanks.
Aw, nevermind. I found it plenty easy to just create the Inserted and LastModified columns in each table myself, set a default value for each, and build an update trigger for LastModified. That seems to be what people do, and the Change Tracking looks like it's mainly set up for sync'ing. Right?
OK, this works beautifully (also see this article)...
public partial class MyEntities
{
partial void OnContextCreated()
{
this.SavingChanges += new System.EventHandler(CustomSavingChangesLogic);
}
/// <summary>
/// Apply timestamps
/// </summary>
public void CustomSavingChangesLogic(object sender, System.EventArgs e)
{
var changedEntities = ((ObjectContext)sender).ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified);
foreach (var stateEntryEntity in changedEntities)
{
if(!stateEntryEntity.IsRelationship) {
var entity = stateEntryEntity.Entity;
var lastModifiedPropInfo = entity.GetType().GetProperty("LastModified");
if (lastModifiedPropInfo != null)
lastModifiedPropInfo.SetValue(entity, DateTime.UtcNow, null);
if (stateEntryEntity.State == EntityState.Added)
{
var createdPropInfo = entity.GetType().GetProperty("Created");
if (createdPropInfo != null)
createdPropInfo.SetValue(entity, DateTime.UtcNow, null);
}
}
}
}
}
I can't seem to find a way to get just the locator object of a column under .Net. It seems that Informix is automatically converting the blob column to Byte[] and not leaving a way to change that behavior.
IBM.Data.Informix.IfxConnection c =
new IBM.Data.Informix.IfxConnection("...");
c.Open();
IBM.Data.Informix.IfxCommand cmd =
new IBM.Data.Informix.IfxCommand("SELECT id,data FROM aaa", c);
IBM.Data.Informix.IfxDataReader r = cmd.ExecuteReader();
while (r.Read()) {
Debug.WriteLine(r.GetValue(1).GetType());
}
c.Close();
results:
System.Byte[]
System.Byte[]
System.DBNull
System.DBNull
I expected:
IBM.Data.Informix.IfxBlob
or something similar.
I asked a colleague about this, and this is his response to me. Since it isn't my handiwork, I've made the answer 'Community Wiki' so I don't get the credit (beyond knowing where to ask).
To answer the question... the following program was written using the Common Informix Provider (the IBM.Data.Informix.dll which uses the DRDA communication protocol... you can get it in the "IBM Data Server Driver for CLI, ODBC, and .NET" package). Something very similar should be able to be done with the Legacy Informix Provider (the IBM.Data.Informix.dll which uses the SQLI communication protocol... you can get it in the "Informix Client SDK" package).
Here's an example program:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using IBM.Data.Informix;
namespace InformixClob
{
class Program
{
static void Main(string[] args)
{
try
{
IfxConnection tConn = new IfxConnection("database=idsdb;server=my-system:9089;uid=informix;pwd=********");
tConn.Open();
IfxCommand tCmd = tConn.CreateCommand();
// create table mytesttab (col1 integer, col2 clob)
tCmd.CommandText = "select * from mytesttab";
IfxDataReader tRdr = tCmd.ExecuteReader();
while (tRdr.Read())
{
Console.WriteLine("Col1 is a {0}", tRdr.GetValue(0).GetType());
Console.WriteLine("Col2(GetValue) is a {0}", tRdr.GetValue(1).GetType());
Console.WriteLine("Col2(GetIfxValue) is a {0}", tRdr.GetIfxValue(1).GetType());
Console.WriteLine("Col2(GetIfxClob) is a {0}", tRdr.GetIfxClob(1).GetType());
}
tRdr.Close();
tConn.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
Console.Write("Press ENTER"); Console.ReadLine();
}
}
}
}
And here's the output it generates:
Col1 is a System.Int32
Col2(GetValue) is a System.String
Col2(GetIfxValue) is a IBM.Data.Informix.IfxClob
Col2(GetIfxClob) is a IBM.Data.Informix.IfxClob
Press ENTER
The IfxDataReader.GetValue(int) method is going to return the column value in a native .NET Framework data type. To get the column value returned as an Informix type, you must request that it be returned as such by either calling the GetIfxValue(int) method, or if you can be more specific, by the GetIfxClob(int) method.