I have been building a Windows Phone 8 app and Windows Azure cloud service that will allow people to store schedules in the cloud. I have implemented a single sign on system and a cloud service used to store the schedule items.
I have however run into yet another problem, as I am using a cloud service to communicate with the database, the commands are slightly different, for example, this is the code to add a record to the database:
public bool addMedication(string userid, string medname, DateTime medtime)
{
using (var meds = new TMP_Meds_Entities())
{
meds.med_schedule.Add(new med_schedule()
{
userid = userid,
medname = medname,
medtime = medtime
});
meds.SaveChanges();
return true;
}
}
I now need to implement methods to allow a user to edit or delete a particular record in the database, does anybody know how I might go about editing or deleting a record? As a note, I am using EntityFramework.
Thanks
This is more or less from scratch, so you'll need to adapt it to your scenario, but this should get you started...
Update:
public void UpdateMed(meds med)
{
if (ModelState.IsValid)
{
db.meds.Attach(med);
db.Entry(med).State = EntityState.Modified;
db.SaveChanges();
}
}
Delete:
public void DeleteMed(int medid)
{
meds med = db.meds.Find(medid);
db.meds.Remove(med);
db.SaveChanges();
}
Here are a couple good resources for more detail
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-basic-crud-functionality-with-the-entity-framework-in-asp-net-mvc-application
http://www.dotnetcurry.com/showarticle.aspx?ID=619
Related
In short:
I have a C# console app which i used to test and write data from SQL to SharePoint lists.
Everything works fine while it is ran as console app. I get the connection towards SQL, context is created, then I connect to SharePoint site and proceed with update of certain fields.
Now, when I deploy working solution as a timerjob (a .wsp) for sharepoint, and when I update it to the server farm and deploy it as feature to the site, and run it as a timerjob, it does work, but only, so to speak "once".
When I run that timer job, it recives SQL context, connects, and updates SharePoint lists. But when I change data in a SQL table (eg. a field called "price" from 10.99 to 11.99), and run timerjob again, it still only updates the "old" data, to be exact, the 10.99 value.
Now when doing this with console app .exe, on the server, no matter how many db changes I perform, it always updates the newest data, but as a timerJob it seems like it "hanges" onto previous context connection, and updates previous data only.
Do I need to specify, in the code, to drop context after the timerjob has ended it's run, so it can call the same but "fresh" context on the next run.
Here is inital code in the .wsp
class TimerJobPromoToolsDefinition : SPJobDefinition
{
public TimerJobPromoToolsDefinition() : base()
{
}
public TimerJobPromoToolsDefinition(string jobName, SPService service) : base(jobName, service, null, SPJobLockType.None)
{
this.Title = "PromoTools_Timer_Job";
}
public TimerJobPromoToolsDefinition(string jobName, SPWebApplication webapp) : base(jobName, webapp, null, SPJobLockType.ContentDatabase)
{
this.Title = "PromoTools_Timer_Job";
}
public override void Execute(Guid targetInstanceId)
{
System.Diagnostics.Trace.Assert(false);
Main();
}
private static TimerJobConnection _context;
public static void Main()
{
PrintInitializing();
_context = new TimerJobConnection();
string siteURL = "http://somesite.com/";
try
{
using (SPSite site = new SPSite(siteURL))
{
using (SPWeb web = site.OpenWeb())
{
var catalogs = GetArtikliFromPromoTools(web);
var articlesFiltered = GetArtikliFromDB(catalogs);
PrintFinishedLoadingArticles();
GetSharePointCatalogHeaders(web);
UpdateArticles(catalogs, articlesFiltered, web);
PrintEndOfOperation();
Console.WriteLine("Press any key to continue...");
}
}
}
catch (Exception)
{
PrintErrorSharepointConnection();
PrintPressKeyToExit();
}
finally
{
}
}
I think the "context" should not the issue based on my experience.
As you catched the exception, try to check is any exception, You could try to debug the code by attaching to owstimer process also.
How does one get the results of a "Saved Search" of Type "Deleted Record" in NetSuite? Other search types are obvious(CustomerSearchAdvanced, ItemSearchAdvanced, etc...) but this one seems to have no reference online, just documentation around deleting records, not running saved searches on them.
Update 1
I should clarify a little bit more what I'm trying to do. In NetSuite you can run(and Save) Saved Search's on the record type "Deleted Record", I believe you are able to access at least 5 columns(excluding user defined ones) through this process from the web interface:
Date Deleted
Deleted By
Context
Record Type
Name
You are also able to setup search criteria as part of the "Saved Search". I would like to access a series of these "Saved Search's" already present in my system utilizing their already setup search criteria and retrieving data from all 5 of their displayed columns.
The Deleted Record record isn't supported in SuiteTalk as of version 2016_2 which means you can't run a Saved Search and pull down the results.
This is not uncommon when integrating with NetSuite. :(
What I've always done in these situations is create a RESTlet (NetSuite's wannabe RESTful API framework) SuiteScript that will run the search (or do whatever is possible with SuiteScript and not possible with SuiteTalk) and return the results.
From the documentation:
You can deploy server-side scripts that interact with NetSuite data
following RESTful principles. RESTlets extend the SuiteScript API to
allow custom integrations with NetSuite. Some benefits of using
RESTlets include the ability to:
Find opportunities to enhance usability and performance, by
implementing a RESTful integration that is more lightweight and
flexible than SOAP-based web services. Support stateless communication
between client and server. Control client and server implementation.
Use built-in authentication based on token or user credentials in the
HTTP header. Develop mobile clients on platforms such as iPhone and
Android. Integrate external Web-based applications such as Gmail or
Google Apps. Create backends for Suitelet-based user interfaces.
RESTlets offer ease of adoption for developers familiar with
SuiteScript and support more behaviors than NetSuite's SOAP-based web
services, which are limited to those defined as SuiteTalk operations.
RESTlets are also more secure than Suitelets, which are made available
to users without login. For a more detailed comparison, see RESTlets
vs. Other NetSuite Integration Options.
In your case this would be a near trivial script to create, it would gather the results and return JSON encoded (easiest) or whatever format you need.
You will likely spend more time getting the Token Based Authentication (TBA) working than you will writing the script.
[Update] Adding some code samples related to what I mentioned in the comments below:
Note that the SuiteTalk proxy object model is frustrating in that it
lacks inheritance that it could make such good use of. So you end with
code like your SafeTypeCastName(). Reflection is one of the best tools
in my toolbox when it comes to working with SuiteTalk proxies. For
example, all *RecordRef types have common fields/props so reflection
saves you type checking all over the place to work with the object you
suspect you have.
public static TType GetProperty<TType>(object record, string propertyID)
{
PropertyInfo pi = record.GetType().GetProperty(propertyID);
return (TType)pi.GetValue(record, null);
}
public static string GetInternalID(Record record)
{
return GetProperty<string>(record, "internalId");
}
public static string GetInternalID(BaseRef recordRef)
{
PropertyInfo pi = recordRef.GetType().GetProperty("internalId");
return (string)pi.GetValue(recordRef, null);
}
public static CustomFieldRef[] GetCustomFieldList(Record record)
{
return GetProperty<CustomFieldRef[]>(record, CustomFieldPropertyName);
}
Credit to #SteveK for both his revised and final answer. I think long term I'm going to have to implement what is suggested, short term I tried implementing his first solution("getDeleted") and I'd like to add some more detail on this in case anyone needs to use this method in the future:
//private NetSuiteService nsService = new DataCenterAwareNetSuiteService("login");
//private TokenPassport createTokenPassport() { ... }
private IEnumerable<DeletedRecord> DeletedRecordSearch()
{
List<DeletedRecord> results = new List<DeletedRecord>();
int totalPages = Int32.MaxValue;
int currentPage = 1;
while (currentPage <= totalPages)
{
//You may need to reauthenticate here
nsService.tokenPassport = createTokenPassport();
var queryResults = nsService.getDeleted(new GetDeletedFilter
{
//Add any filters here...
//Example
/*
deletedDate = new SearchDateField()
{
#operator = SearchDateFieldOperator.after,
operatorSpecified = true,
searchValue = DateTime.Now.AddDays(-49),
searchValueSpecified = true,
predefinedSearchValueSpecified = false,
searchValue2Specified = false
}
*/
}, currentPage);
currentPage++;
totalPages = queryResults.totalPages;
results.AddRange(queryResults.deletedRecordList);
}
return results;
}
private Tuple<string, string> SafeTypeCastName(
Dictionary<string, string> customList,
BaseRef input)
{
if (input.GetType() == typeof(RecordRef)) {
return new Tuple<string, string>(((RecordRef)input).name,
((RecordRef)input).type.ToString());
}
//Not sure why "Last Sales Activity Record" doesn't return a type...
else if (input.GetType() == typeof(CustomRecordRef)) {
return new Tuple<string, string>(((CustomRecordRef)input).name,
customList.ContainsKey(((CustomRecordRef)input).internalId) ?
customList[((CustomRecordRef)input).internalId] :
"Last Sales Activity Record"));
}
else {
return new Tuple<string, string>("", "");
}
}
public Dictionary<string, string> GetListCustomTypeName()
{
//You may need to reauthenticate here
nsService.tokenPassport = createTokenPassport();
return
nsService.search(new CustomListSearch())
.recordList.Select(a => (CustomList)a)
.ToDictionary(a => a.internalId, a => a.name);
}
//Main code starts here
var results = DeletedRecordSearch();
var customList = GetListCustomTypeName();
var demoResults = results.Select(a => new
{
DeletedDate = a.deletedDate,
Type = SafeTypeCastName(customList, a.record).Item2,
Name = SafeTypeCastName(customList, a.record).Item1
}).ToList();
I have to apply all the filters API side, and this only returns three columns:
Date Deleted
Record Type(Not formatted in the same way as the Web UI)
Name
I am trying to store emails into my SQL server database. These emails I got from Exchange Webservices.
I am using entity Framework and made a ADO .Net Data Model.
My Question is how do I make a method(StoreEmail) that stores these emails into my database.
This is my StoreEmail method that I got so far:
It should store my PhishingMails...
public object StoreMail(Model.PhishingMail PhishingMail)
{
using (var phishingMailStorage = new PhishFinderModel())
{
PhishingMail = MailMapper.Map(Model.PhishingMail);
phishingMailStorage.PhishingMails.Add();
phishingMailStorage.SaveChanges();
return PhishingMail;
}
}
In Mailmapper class I set the properties that I want to store, which are Sender, Subject and Body:
public static PhishingMail Map(EmailMessage OutlookMail)
{
PhishingMail readMail = new PhishingMail();
readMail.Sender = OutlookMail.Sender.Address;
readMail.Body = OutlookMail.Body;
return readMail;
}
This is my DB schema
To clarify my question, I already get the list of emails from the exchange server. Now, all I need to do is insert them into the SQL server.
How do I make my StoreEmail method work to do this?
Please don't be harsh I am really new to this. It feels like I am swimming in an ocean of information and I don't know where to look or start. So any suggested tutorials are very welcome.
Thanks!
You're storing PhishingMail, and you're receiving a PhishingMail, so you don't need your mapping step.
Does this not work?
public void StoreMail(Model.PhishingMail PhishingMail)
{
using (var phishingMailStorage = new PhishFinderModel())
{
phishingMailStorage.PhishingMails.Add(PhishingMail);
phishingMailStorage.SaveChanges();
}
}
You don't need to return the mail, either, since the caller already has it (and it's a lot tidier to have a void return if you're not returning a new/different object.
If you actually need to store an EmailMessage, your method should be:
public void StoreMail(EmailMessage emailMessage)
{
var phishingMail = MailMapper.Map(emailMessage);
using (var phishingMailStorage = new PhishFinderModel())
{
phishingMailStorage.PhishingMails.Add(phishingMail);
phishingMailStorage.SaveChanges();
}
}
If I am logged into Windows 8 as a non-admin, such as the guest account, will this database creation code fail? If so, how can I change it works with non-admin users:
protected List<Order> orders;
string dbName;
#region Constructors
public RestaurantRepository()
{
Initialize();
}
protected void Initialize()
{
dbName = "db_sqlite-net.db3";
// check the database, if it doesn't exist, create it
CheckAndCreateDatabase(dbName);
}
#endregion
#region Database
protected string GetDBPath()
{
string dbRootPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
return Path.Combine(dbRootPath, "menufinderwin8.db");
}
// This method checks to see if the database exists, and if it doesn't, it creates
// it and inserts some data
protected void CheckAndCreateDatabase(string dbName)
{
// create a connection object. if the database doesn't exist, it will create
// a blank database
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(GetDBPath());
conn.CreateTableAsync<Order>();
conn.CreateTableAsync<Order>();
conn.CreateTableAsync<OrderDetail>();
conn.CreateTableAsync<Product>();
conn.CreateTableAsync<Restaurant>();
//using (SQLiteConnection db = new SQLiteConnection(GetDBPath()))
//{
// create the tables
// db.CreateTable<Order>();
//db.CreateTable<OrderDetail>();
//db.CreateTable<Product>();
//db.CreateTable<Restaurant>();
// close the connection
//db.Close();
//}
}
I think as long as the app is installed for all users, it should have access to its own local directory. I don't think you'd be able to share the database between the users, but I don't think it'd fail.
Let me know how it turns out, I'm curious :)
I have a few tables in SQL Server that I am using to log when a user logs into a Silverlight application.
I have created an entity for each of those tables. One example is ApplicationUsageLog, where I log the ApplicationID, the Date, and the UserID. Those are mostly pulled from the Silverlight side.
I would like to just create a method called Login(AppID,UserID) that can do an insert into that table.
Is that possible?
Thanks!
EDIT The following does not work for some reason:
[Invoke]
public void Login(int AppID,string EmployeeNo)
{
var aul = new ApplicationUsageLog{ ApplicationID = AppID, LoginDate = System.DateTime.Now, EmployeeNo = EmployeeNo };
if ((aul.EntityState != System.Data.EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(aul, System.Data.EntityState.Added);
}
else
{
try
{
this.ObjectContext.ApplicationUsageLogs.AddObject(aul);
}
catch (System.Exception e) { }
}
}
I can look at aul and all looks good. But when I put a breakpoint at the end, this.ObjectContext.ApplicationUsageLogs is still totally empty....
Yes, you can add a method to your Domain service class marked with the InvokeAttribute attribute. The method will appear as a method on the client context class.
You can add your own custom methods to the DomainService if you want but it will not be called automatically when you insert into your context and SubmitChanges. You will have to call it manually.
If you want to override the implementation of your Insert method you can simply modify the contents of the Insert*EntityName* method in your DomainService.