C# Entity Framework MVC Web API - c#

I have searched and searched and cannot find any answers. Hopefully you all can be of assistance.
I am building an MVC WebAPI app in C#.
I have added a DB connection using Entity Framework and am able to call it and load a variable with the data.
My issue is that I am trying to return the data in JSON format (I already added the line of code to my WebApiConfig.cs file to default to text/html).
Here is my code:
public string Get(string id)
{
string userName = id.ToString();
using (var db = new SDCLogins())
{
var query = from logins in db.logins
join loginTypes in db.loginTypes on new { loginType = logins.loginType } equals new { loginType = loginTypes.loginTypeID }
where
logins.uname == userName
select new
{
logins.login1,
startDate = SqlFunctions.DatePart("mm", logins.startDate) + "/" +
SqlFunctions.DateName("dd", logins.startDate) + "/" +
SqlFunctions.DateName("yyyy", logins.startDate),
stopDate = SqlFunctions.DatePart("mm", logins.stopDate) + "/" +
SqlFunctions.DateName("dd", logins.stopDate) + "/" +
SqlFunctions.DateName("yyyy", logins.stopDate),
createdDate = SqlFunctions.DatePart("mm", logins.createdDate) + "/" +
SqlFunctions.DateName("dd", logins.createdDate) + "/" +
SqlFunctions.DateName("yyyy", logins.createdDate),
logins.createdBy,
loginTypes.loginDescription
};
return Json.Encode(query);
}
}
When I execute the response I get is different than any JSON I've seen before:
"[{\"login1\":\"akamau001\",\"startDate\":\"1/24/2014\",\"stopDate\":\"//\",\"createdDate\":\"10/3/2014\",\"createdBy\":\"ozzie\",\"loginDescription\":\"Login Type 1\"},{\"login1\":\"123D56\",\"startDate\":\"1/1/1900\",\"stopDate\":\"//\",\"createdDate\":\"10/3/2014\",\"createdBy\":\"ozzie\",\"loginDescription\":\"Login Type 2\"}]"
Firstly the // is the way I am handling the dates, any insite as to how to make those return null would be appreciated. Secondly why is everything escaped with a "\"? Is there any way to turn that off?

Fixed the date issue by:
startDate = logins.startDate.HasValue ? (object) logins.startDate.Value.ToShortDateString() : DBNull.Value,
stopDate = logins.stopDate.HasValue ? (object) logins.stopDate.Value.ToShortDateString() : DBNull.Value,
createdDate = logins.createdDate.HasValue ? (object) logins.createdDate.Value.ToShortDateString() : DBNull.Value
Now it doesn't flip out if there is a value or if there isn't.
Also for the JSON issue:
public Array Get(string id)
{
//return "value";
string userName = id.ToString();
using (var db = new SDCLogins())
{
var query = from logins in db.logins.AsEnumerable()
join loginTypes in db.loginTypes on new { loginType = logins.loginType } equals new { loginType = loginTypes.loginTypeID }
where
logins.uname == userName
select new
{
logins.login1,
startDate = logins.startDate.HasValue ? (object) logins.startDate.Value.ToShortDateString() : DBNull.Value,
stopDate = logins.stopDate.HasValue ? (object) logins.stopDate.Value.ToShortDateString() : DBNull.Value,
createdDate = logins.createdDate.HasValue ? (object) logins.createdDate.Value.ToShortDateString() : DBNull.Value,
logins.createdBy,
loginTypes.loginDescription
};
return query.ToArray();
}
}
Once I set the type as an array and then converted query to an array and returned that it works very much like I expected it to!
Although I didn't get a solid answer you all helped me find my way! Thanks a ton!!

Related

Cannot use SqlGeography as parameter with Dapper and ASP.NET core

I'm trying to insert a 'geography' datatype in SQL Server using Dapper 1.50.2 with ASP.NET Core 2.1.
I've read on several threads that it should be accepted by default since 1.32, yet I receive an exception when trying to insert the data type.
Note: I'm using a non .NET CORE data type in my entity. Microsoft.SqlServer.Types: 14.0.1016.290 since I couldn't find a good .NET core compatible geography datatype. (something with EF Core)
Entity:
public class Address : Entity{
/* .. */
public SqlGeography SpatialLocation { get; set; }
/* .. */
}
Insert method (standard):
public virtual TEntity Insert(TEntity entity){
if (string.IsNullOrEmpty(entity.CreationUser)){
entity.CreationUser = "UNKNOWN";
}
if (entity.EndDate == default(DateTime)){
entity.EndDate = DateTime.MaxValue;
}
return (TEntity) DapperExtensionsProxy.Insert(entity);
}
Insert method (specialized):
public override Address Insert(Address entity){
if (entity == null){
throw new ArgumentNullException(nameof(entity));
}
var sql = $"INSERT INTO [dbo].[Address]"
+ "([CreationDate]"
+ ",[StartDate]"
+ ",[UpdateDate]"
+ ",[EndDate]"
+ ",[CreationUser]"
+ ",[UpdateUser]"
+ ",[CityId]"
+ ",[Street]"
+ ",[Street2]"
+ ",[SpatialLocation]"
+ ",[Flags])"
+ "VALUES"
+ "(#creationDate"
+ ",#startDate"
+ ",#endDate"
+ ",#creationUser"
+ ",#cityId"
+ ",#street"
+ ",#street2"
+ ",#spatial"
+ ",#flags);";
DapperExtensionsProxy.Execute(sql, new
{
creationDate = entity.CreationDate,
startDate = entity.StartDate,
endDate = entity.EndDate,
creationUser = entity.CreationUser,
cityId = entity.CityId,
street = entity.Street,
street2 = entity.Street2,
flags = entity.Flags,
spatial = entity.SpatialLocation
});
/* should get ID back, check with SELECT SCOPE_IDENTITY() */
return entity;
}
I've also tried the Dynamic parameters approach with dapper (from the first post) but I'm unsure how to apply them together with different parameters
Exception
The member spatial of type Microsoft.SqlServer.Types.SqlGeography cannot be
used as a parameter value
UPDATE
I've solved this through a work-around with this piece of code. Getting the syntax right proved difficult.
public override Address Insert(Address entity){
if (entity == null){
throw new ArgumentNullException(nameof(entity));
}
var sql = $"INSERT INTO [dbo].[Address]"
+ "([CreationDate]"
+ ",[StartDate]"
+ ",[EndDate]"
+ ",[CreationUser]"
+ ",[CityId]"
+ ",[Street]"
+ ",[Street2]"
+ ",[SpatialLocation]"
+ ",[Flags])"
+ "VALUES"
+ "(#creationDate"
+ ",#startDate"
+ ",#endDate"
+ ",#creationUser"
+ ",#cityId"
+ ",#street"
+ ",#street2"
+ ",#spatial "
+ ",#flags); "
+ "SELECT SCOPE_IDENTITY()";
string lat = entity.SpatialLocation.Lat.Value.ToString(CultureInfo.InvariantCulture);
string longitude = entity.SpatialLocation.Long.Value.ToString(CultureInfo.InvariantCulture);
entity.Id = DapperExtensionsProxy.ExecuteScalar<int>(sql,new{
creationDate = entity.CreationDate,
startDate = entity.StartDate,
endDate = entity.EndDate,
creationUser = entity.CreationUser,
cityId = entity.CityId,
street = entity.Street,
street2 = entity.Street2,
flags = entity.Flags,
spatial = $"POINT({lat} {longitude} 4326)"
});
return entity;
}

how to add list of object and return it

Here i am getting the all post and comment accoding to friendID its working fine,my problem is when i debugg it shows me 2 or more data in GetAllPost but its return only last data,i am not getting why its not returning all data at once need help..
public dynamic getalldetails(int friendsid)
{
var GetAllPost = (dynamic)null;
FriendsId =dbContext.Usertable.where(u=>u.userID==friendsid).tolist();
if(FriendsId!=null)
foreach(var item in FriendsId )
{
GetAllPost = (from post in db.Posts.where(item.userID==post.userID).ToList()
orderby post.PostedDate descending
select new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = post.UserProfile.UserName,
PostedByAvatar =imgFolder + (String.IsNullOrEmpty(post.UserProfile.AvatarExt) ? defaultAvatar : post.PostedBy + "." + post.UserProfile.AvatarExt),
PostedDate = post.PostedDate,
PostId = post.PostId,
PostComments = from comment in post.PostComments.ToList()
orderby comment.CommentedDate
select new
{
CommentedBy = comment.CommentedBy,
CommentedByName = comment.UserProfile.UserName,
CommentedByAvatar = imgFolder +(String.IsNullOrEmpty(comment.UserProfile.AvatarExt) ? defaultAvatar : comment.CommentedBy + "." + comment.UserProfile.AvatarExt),
CommentedDate = comment.CommentedDate,
CommentId = comment.CommentId,
Message = comment.Message,
PostId = comment.PostId
}
}).AsEnumerable();
}
return GetAllPost;
}
Each time through the loop, you're assigning to GetAllPost, thereby throwing away whatever it held before. You need to accumulate posts -- something along these lines:
ArrayList GetAllPost = new ArrayList();
...
foreach (var item in FriendsId)
{
GetAllPost.AddRange(from post in
// Your LINQ code
...);
}
return GetAllPost;

C# Linq with four tables and one foreign key that isn´t always needed

I have the problem that I have a MariaDB database with HeidiSQL. There are four tables and im using Linq to insert new data. One of the tables isn´t always necessary. So i marked the column with the foreign key in one of the a other tables for can be NULL. The problem is that when i create the new objects to insert into database it creates the new data in the database but the foreign key in the other table keeps emtpy.
When i undo the Null option in the column and want to insert a standardvalue instead, it throws an UpdateEntityException.
What i should mention is, that i cerated the database first in HeidiSQL and created then the code in Visual Studio with EntityFramework 5.0.
Or might the mistake caused by building and adding the database object in an if-clause?
There are some code examples of my code, i hope it will help.
DateTime aktuellesDatum = DateTime.Now;
int proId = getProjectIdByProjectnumber(zeichnungen[0].Projektnummer);
int tagId = getTagIdByTag(zeichnungen[0].Tag, zeichnungen[0].Projektnummer);
string hauptzeichnung = "";
int gruppeId = -1;
//Noch kein Projekt vorhanden
if(proId == -1)
{
using (DMSContext db = new DMSContext())
{
foreach (ZeichnungInDB zeichnungInDB in zeichnungen)
{
zeichnungInDB.Volante_Index = getVolCountByDrawingNumber(zeichnungInDB.Zeichnungsnummer) + 1;
var zeichnung = new zeichnung()
{
Zeichnung_ID = zeichnungInDB.Dateiname + "_" + zeichnungInDB.Index + "_VOL_" + zeichnungInDB.Volante_Index + "_" + aktuellesDatum.ToShortDateString(),
Zeichnungsnummer = zeichnungInDB.Zeichnungsnummer,
Index = zeichnungInDB.Index,
Zeitstempel = aktuellesDatum,
Dateiname_Org = zeichnungInDB.Dateiname,
Aenderung_Ext = zeichnungInDB.Aenderung_Ext,
Aenderung_Int = "AE_" + zeichnungInDB.Projektnummer + "_" + aktuellesDatum.Year + "-" + aktuellesDatum.Month + "-" + aktuellesDatum.Day + " " + aktuellesDatum.Hour + ":" + aktuellesDatum.Minute,
Dokumententyp = zeichnungInDB.DokumentenTyp,
Dateiendung = zeichnungInDB.Extension,
Volante_Index = zeichnungInDB.Volante_Index,
MMS_Sachmerkmal = zeichnungInDB.Mms_Sachmerkmal,
Status = zeichnungInDB.Status,
Aenderung_Bemerkung_Txt = zeichnungInDB.Aenderung_Bemerkung_Text,
Einzel_Bemerkung_Txt = zeichnungInDB.Einzel_Bemerkung,
Ahang_Link = zeichnungInDB.Anhang_Link,
Einzel_Link = zeichnungInDB.Einzel_Link,
};
db.zeichnungs.Add(zeichnung);
if(zeichnungInDB.Baugruppe_Hauptzeichnung == true)
{
hauptzeichnung = zeichnungInDB.Zeichnungsnummer;
}
}
var projekt = new projekt()
{
Projektnummer = zeichnungen[0].Projektnummer,
};
var tag = new tag()
{
Tag1 = zeichnungen[0].Tag,
};
if (!hauptzeichnung.Equals(""))
{
var baugruppe = new baugruppe
{
Hauptzeichnung = hauptzeichnung,
};
db.baugruppes.Add(baugruppe);
}
db.projekts.Add(projekt);
db.tags.Add(tag);
try
{
db.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
// raise a new exception nesting
// the current instance as InnerException
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
}
This is only a short e.g. from my code because the whole cs would be to long and nobody would spend the time on so much code.
One other thing i would like to ask is. If the following code works correct for update a string in a field?
private static void updateHauptzeichnung(int baugruppeId, string zeichnungsnummer)
{
using (var context = new DMSContext())
{
var query = context.baugruppes
.Where(b => b.Baugruppe_ID == baugruppeId)
.Select(g => new { g.Hauptzeichnung })
.SingleOrDefault();
if (query != null)
{
query.Hauptzeichnung.Replace(query.Hauptzeichnung, zeichnungsnummer);
}
context.SaveChanges();
}
}
I solved my problem. I changed the foreignkey field from can be NULL to is necessary, added in the foreign table a costum dataset with ID is 0 and I give new data this ID as its foreign ID when they have no offical link to the foreign table. It might not be the best solution, but it fixed my problem.

Getting Linked Server Database Tables and Views via SMO

How do I get SQL Server databases that are on a Linked Server via SMO?
Server server = GetServer("server");
Database db = server.Databases["db"];
LinkedServer ls = server.LinkedServers["ls"];
The second line above returns a regular database. The third line returns a particular linked server, which provides access to the linked server connection, but not to its data. How can I get something like:
Database db1 = server.LinkedServers["ls"].Databases["db"];
? The reason I need this is that I will be looping through different objects within the linked database, such as tables or views.
UPDATE
For further clarification, I currently have this code:
public void GenerateViews(string objectName = null)
{
Server server = new Server("server");
//Database a = server.Databases["a"];
Database b = server.Databases["b"];
b.Tables.OfType<Table>().ToList().ForEach(o => ProcessSqlObject(o));
b.Views.OfType<View>().ToList().ForEach(o => ProcessSqlObject(o));
}
//takes all tables and views in database b that have a custom extended property "CreateView", and create a view for it in database a
private void ProcessSqlObject(dynamic o) //o MUST be an SMO table or view (since they don't implement a common interface, I'm using a dynamic)
{
Database ct = (Database)o.Parent;
Database a = ct.Parent.Databases["a"];
const string viewPrefix = "V_CTC_";
const string SourceIDColumnName = "SourceID";
string objectName = (string)o.Name; //name of table or view
objectName = objectName.StartsWith("V_", StringComparison.InvariantCultureIgnoreCase) ? objectName.Substring(2) : objectName;
string viewName = viewPrefix + objectName; //remove V_ from view, so that we don't have "V_V_".
ExtendedProperty ep = (ExtendedProperty)o.ExtendedProperties["CreateView"];
bool AlreadyExists = a.Views.OfType<View>().Any(v => v.Name == viewName);
if (ep != null && ep.Value.ToString() == "1") //there IS an extended property, and its value is 1, meaning, we want a view
{
if (!AlreadyExists) //we don't already have the view
{
//ProcessSqlObject(t, viewName, SourceIDColumnName, ct, a);
StringBuilder ws = new StringBuilder();
ws.AppendLine("SELECT");
ws.AppendLine("\t2 [" + SourceIDColumnName + "]");
((ColumnCollection)o.Columns).OfType<Column>().ToList().ForEach(c =>
{
ws.AppendLine("\t, [" + c.Name + "]");
});
string linkedServer = "[ls].";
ws.AppendLine("FROM " + linkedServer + "[" + ct.Name + "].[dbo].[" + o.Name + "] WITH(NOLOCK)");
string rt = ws.ToString();
rt = rt.Replace("wholesale", "retail");
rt = rt.Replace("2 [" + SourceIDColumnName + "]", "3 [" + SourceIDColumnName + "]");
StringBuilder sql = new StringBuilder();
sql.AppendLine("CREATE VIEW " + viewName + " AS");
sql.AppendLine();
sql.AppendLine(ws.ToString());
//sql.AppendLine();
sql.AppendLine("UNION ALL");
sql.AppendLine();
sql.AppendLine(rt);
Console.WriteLine(sql);
a.ExecuteNonQuery(sql.ToString());
}
}
else //we DON't want the view
{
a.Views.OfType<View>().Single(v => v.Name == viewName).Drop();
a.Refresh();
}
}
}
I am currently passing to the second function all tables and views in a given database. This is withOUT using a linked server. I want the ability to do the same thing but for a linked server, without having to rewrite the code.
Thanks.
You don't need to connect to the server to get the tables and views (if you just need their names). The LinkedServer class provide the EnumTables method for that.
The LinkedServer class has a DataSource property that you should be able to use as the name of the remote server. If you pass this to your GetServer() function, you should get back an SMO Server object.

Create an Array from SQL Query Results

I have the following function that searches a database for entries where a column called "description" have the same value. Right now it just returns the first value it finds or a default value is there isn't one.
public static NewCode GetAltCode(int altCodeVer, string descrip)
{
var sql = #"select Code, Description, VersionID from Code.CodeLookup where versionid=#vers and description=#description";
return ObjectFactory.GetInstance<IDatabaseFactory>().Query<NewCode>(sql, new { vers = altCodeVer, description = descrip, }).FirstOrDefault();
}
I have this if statement to check and make sure the result isn't null, and if it is, to say that the "code isn't found"
[Authorize(parentAction: "Edit")]
public ActionResult Lookup(string Code, int? VersionId = null)
{
var Info = VisitViews.GetDescriptionByVersionId(Code, VersionId.HasValue ? VersionId.Value : 9);
var description = string.Empty;
// CHECK FOR NULL
if (Info != null)
{
description = Info.Description;
if (VersionId == 9)
{
var altInfo = VisitViews.GetAltCode(10, description);
}
if (VersionId == 10)
{
var altInfo = VisitViews.GetAltCode(9, description);
}
}
else
description = "CODE NOT FOUND";
return Json(new { Description = description });
}
My question is, instead of doing FirstOrDefault, is there a way to store the results in an array (or even to store them in a list and call ToArray on the list)? I'm trying to get all of the codes received during the sql search instead of just one so that another function I am working on can traverse the array and place the items where they need to be in a UI.
For future reference of this post, here is the answer:
Change the return type to NewCode[] and replace .FirstOrDefault() with .ToArray()
public static NewCode[] GetAltCode(int altCodeVer, string descrip)
{
var sql = #"select Code, Description, VersionID from Code.CodeLookup where versionid=#vers and description=#description";
return ObjectFactory.GetInstance<IDatabaseFactory>().Query<NewCode>(sql, new { vers = altCodeVer, description = descrip, }).ToArray();
}

Categories