Posting data to sql server using servicestack and c# - c#

I'm just starting to learn servicestack and c# and I need some help with posting data to sql server. When I test using swagger I get a 200 response but nothing is actually being inserted into the database and I'm not sure where I'm going wrong.
Model.Type
public class Book
{
[PrimaryKey]
[AutoIncrement]
public int BookID { get; set; }
public string Author { get; set; }
public string Title { get; set; }
public int NumberOfPages { get; set; }
public int Isbn { get; set; }
}
Manager Interface:
namespace ServiceStackServiceLog4NetTemplate.Interfaces.Managers
{
public interface IPostBookManager
{
Book CreateBooks();
}
}
Repository Interface:
namespace ServiceStackServiceLog4NetTemplate.Interfaces.Repositories
{
public interface IPostBookRepository
{
Book PostBooks();
}
}
Messages.Request
namespace ServiceStackServiceLog4NetTemplate.ServiceModel.Messages
{
[Route("/PostBooks", Verbs = "POST")]
public class PostBooksRequest
{
[AutoIncrement]
public int BookID { get; set; }
public string Author { get; set; }
public string Title { get; set; }
public int NumberOfPages { get; set; }
public int Isbn { get; set; }
}
}
Messages.Response
namespace ServiceStackServiceLog4NetTemplate.ServiceModel.Messages
{
public class PostBooksResponse : IHasResponseStatus
{
public Book Book { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
}
Manager
class PostBooksManager : IPostBookManager
{
private IPostBookRepository postRepo;
public PostBooksManager(IPostBookRepository pRepo)
{
postRepo = pRepo;
}
public Book CreateBooks()
{
var bookCreations = postRepo.PostBooks();
return bookCreations;
}
}
}
Repository
namespace ServiceStackServiceLog4NetTemplate.Repositories
{
public class PostBookSqlRepo : IPostBookRepository
{
private readonly string connection = ConfigurationManager.AppSettings["BooksDB"];
public Book PostBooks()
{
var postBooks = CreateBooks();
return postBooks;
}
private Book CreateBooks()
{
var newBooks = new Book();
string query = "INSERT INTO dbo.BooksTable(BookID, Author, Title, NumberOfPages, ISBN)" +
"VALUES(#BookID, #Author, #Title, #NumberOfPages, #ISBN)";
SqlConnection dbConnect = new SqlConnection(connection);
SqlCommand cmd = new SqlCommand(query, dbConnect);
using (dbConnect)
{
dbConnect.Open();
var b = new Book()
{
BookID = newBooks.BookID,
Author = newBooks.Author,
Title = newBooks.Title,
NumberOfPages = newBooks.NumberOfPages,
Isbn = newBooks.Isbn
};
cmd.Parameters.AddWithValue("#BookID", b.BookID);
cmd.Parameters.AddWithValue("#Author", b.Author);
cmd.Parameters.AddWithValue("#Title", b.Title);
cmd.Parameters.AddWithValue("#NumberOfPages", b.NumberOfPages);
cmd.Parameters.AddWithValue("#ISBN", b.Isbn);
dbConnect.Close();
}
return newBooks;
}
}
}
Service Definition
namespace ServiceStackServiceLog4NetTemplate.ServiceDefinition
{
[EnableCors(allowedMethods: "GET,POST,DELETE")]
class PostBooksServiceDefinition : Service
{
private IPostBookManager postManager;
public PostBooksServiceDefinition(IPostBookManager bookP)
{
postManager = bookP;
}
public object Post(PostBooksRequest request)
{
var postBook = request.ConvertTo<Book>();
PostBooksResponse resp = new PostBooksResponse()
{
Book = postBook
};
return resp;
}
}
}

First you shouldn't have [AutoIncrement] on your Request DTO, you're converting the DTO to a Book object which is the data model you're saving, not the Request DTO. (It doesn't have any impact on anything, it's just unnecessary and unused).
Secondly, you're using OrmLite Data Attributes in your Book data model but you're not using OrmLite to insert the record.
To use OrmLite to insert a new Book in your ServiceStack Services you can just use:
Db.Insert(postBook);
If you also need to create the Book RDBMS table, you can create it if it doesn't already exist with:
using (var db = dbFactory.Open())
{
db.CreateTableIfNotExists<Book>();
}
If you haven't registered your OrmLiteConnectionFactory with ServiceStack, you can register it with:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connString, SqlServer2012Dialect.Provider));
See the docs on OrmLite project page for more info:
https://github.com/ServiceStack/ServiceStack.OrmLite
Using a Repository
If you want to use PostBookSqlRepo to save your books you should configure it with your IDbConnectionFactory, e.g:
public class PostBookSqlRepo : IPostBookRepository
{
IDbConnectionFactory dbFactory;
public PostBookSqlRepo(IDbConnectionFactory dbFactory)
{
this.dbFactory = dbFactory;
}
//...
public Book CreateBooks(Book book)
{
using (var db = dbFactory.OpenDbConnection())
{
db.Insert(book);
}
}
}
Which you can configure in your ServiceStack IOC with:
container.Register<IPostBookRepository>(c =>
new PostBookSqlRepo(c.Resolve<IDbConnectionFactory>()));

Related

How to return correct values for listview using WCF?

I want to populate listview with information retrieved from database using WCF in C# and am not able to retrieve correct data for listview binding.
public interface IServicePl
{
[OperationContract]
[OperationContract]
IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments();
}
[DataContract]
public class InterventiiCuEchipament
{
[DataMember]
public string EchipamentInterventie { get; set; }
public int id_interventie { get; set; }
public string tip_interventie { get; set; }
public string responsabil { get; set; }
public DateTime data_finalizare { get; set; }
public bool status { get; set; }
}
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments()
{
try
{
IEnumerable<InterventiiCuEchipament> query = from sel1 in dataP.interventiis
join sel2 in dataP.sesizaris
on sel1.id_interventie equals sel2.id_sesizare
select new InterventiiCuEchipament()
{
id_interventie = sel1.id_interventie,
EchipamentInterventie = sel2.echipament,
tip_interventie = sel2.tip_sesizare,
responsabil = sel1.responsabil,
data_finalizare = (DateTime)sel1.data_finalizare,
status = (bool)sel1.status
};
return query;
}
On the client side I have the following code :
if (client.InnerChannel.State != CommunicationState.Faulted)
{
List<InterventiiCuEchipament> ListaInterventii = new List<InterventiiCuEchipament>();
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();
InterventiiList.ItemsSource = ListaInterventii;
InterventiiList.Items.Refresh();
}
Output from query is ok, like in this image
Output for listview binding is like in this image
Why I can see just the count of query? and not correct values returned by query.
If the query returns values, then ListaInterventii should also have values.
I wrote a similar demo, you can compare it.
You can use foreach to see if there is a value.
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();
foreach(var a in ListaInterventii)
{
int A = a.id_interventie;
}
Demo
public class ProductService : IServicePl
{
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments()
{
// This comes from database.
var _dbCountries = new List<InterventiiCuEchipament>
{
new InterventiiCuEchipament {id_interventie = 1, tip_interventie="1"},
new InterventiiCuEchipament {id_interventie = 2, tip_interventie="2"},
new InterventiiCuEchipament {id_interventie = 3, tip_interventie="3"},
};
return _dbCountries;
}
}
[ServiceContract]
public interface IServicePl
{
[OperationContract]
IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments();
}
[DataContract]
public class InterventiiCuEchipament
{
[DataMember]
[Key]
public int id_interventie { get; set; }
public string tip_interventie { get; set; }
}
client side
ServicePlClient client = new ServicePlClient();
List<InterventiiCuEchipament> ListaInterventii = new List<InterventiiCuEchipament>();
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();

ASP.NET C# OData Service + Navigation Property + $expand = null. What am I missing?

I will try to explain my problem as thoroughly as possible with a simplified example. Please note that I am NOT using Entity Framework.
I have this model:
public class Person
{
[Key]
public Guid Id { get; set; }
public string GivenName { get; set; }
public string FamilyName { get; set; }
public List<Employment> Employments { get; set; }
}
public class Employment
{
public string Role { get; set; }
public Guid? ManagerId { get; set; }
public virtual Person Manager { get; set; }
}
I create an in-memory data source:
public class MyDataSource
{
private static MyDataSource instance = null;
public static MyDataSource Instance
{
get
{
if (instance == null)
{
instance = new MyDataSource();
}
return instance;
}
}
public List<Person> Persons { get; set; }
private MyDataSource()
{
this.Persons = new List<Person>();
this.Persons.AddRange(new List<Person>
{
new Person()
{
Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), //Just for simplicity
GivenName = "John",
FamilyName = "Doe",
Employments = new List<Employment>()
{
new Employment()
{
Role = "Boss"
}
}
},
new Person()
{
Id = Guid.Parse("00000000-0000-0000-0000-000000000002"), //Just for simplicity
GivenName = "Clark",
FamilyName = "Kent",
Employments = new List<Employment>()
{
new Employment()
{
Role = "Worker",
ManagerId = Guid.Parse("00000000-0000-0000-0000-000000000001"), //Just for simplicity
}
}
}
});
}
}
I have this controller:
[EnableQuery]
public class PersonsController : ODataController
{
public IHttpActionResult Get()
{
return Ok(MyDataSource.Instance.Persons)
}
}
I configure the EndPoint:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapODataServiceRoute("ODataRoute", "odata", CreateEdmModel());
config.Select().Expand().Filter().OrderBy().MaxTop(null).Count()
}
public static IEdmModel CreateEdmModel()
{
var builder = new ODataConventionModelBuilder();
var persons = builder.EntitySet<Person>("Persons");
builder.ComplexType<Employment>().HasOptional(e => e.Manager, (e, p) => e.ManagerId == p.Id);
return builder.GetEdmModel();
}
}
Checking the $metadata I see this:
<NavigationProperty Name="Manager" Type = "MyNamespace.Person">
<ReferentialConstraint Property="ManagerId" ReferenceProperty="Id" />
</NavigationProperty
Everything looks fine from what I can tell but:
https://example.com/odata/persons?$expand=Employments/Manager
receives everything fine but:
Manager is null for both persons. I was expecting to see John Doe on Clark Kents employment.
What am I missing?
I have solved it myself.
I realised that it doesn't work like I thought and that I have to add a reference to the manager directly in MyDataSource. After that it works to $expand the manager.

includeDetails not working in ABP Framework

I have a simple project (ABP version: 3.1.2, Database: EF Core).
I run GetAsync:
var author = await _authorRepository.GetAsync(id, includeDetails: true);
But author.Films was not included. What may I have forgotten?
Author (AggregateRoot):
public class Author : FullAuditedAggregateRoot<Guid>
{
public string Name { get; private set; }
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
public List<Film> Films { get; set; }
private Author()
{
Films = new List<Film>();
/* This constructor is for deserialization / ORM purpose */
}
internal Author(
Guid id,
[NotNull] string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
: base(id)
{
Name = name;
BirthDate = birthDate;
ShortBio = shortBio;
Films = new List<Film>();
}
}
Film (Entity):
public class Film : Entity<Guid>
{
public virtual Guid AuthorId { get; internal set; }
public string Name { get; set; }
}
SeedAsync in DataSeeder class (I checked whether data exists in database after DbMigrator ran, there are these data in tables as expected):
public async Task SeedAsync(DataSeedContext context)
{
if (await _authorRepository.GetCountAsync() == 0)
{
var authorId = _guidGenerator.Create();
await _authorRepository.InsertAsync(
new Author(authorId, "J. R. R. Tolkien", DateTime.Now.AddYears(-60), "bio1"),
autoSave: true
);
await _filmRepository.InsertAsync(
new Film { AuthorId = authorId, Name = "The Return of the King1" },
autoSave: true);
await _filmRepository.InsertAsync(
new Film { AuthorId = authorId, Name = "The Return of the King2" },
autoSave: true);
await _filmRepository.InsertAsync(
new Film { AuthorId = authorId, Name = "The Return of the King3" },
autoSave: true);
}
}
AuthorAppService:
public class AuthorAppService : BookStoreAppService, IAuthorAppService
{
private readonly IAuthorRepository _authorRepository;
private readonly AuthorManager _authorManager;
public AuthorAppService(
IAuthorRepository authorRepository,
AuthorManager authorManager)
{
_authorRepository = authorRepository;
_authorManager = authorManager;
}
public async Task<AuthorDto> GetAsync(Guid id)
{
var author = await _authorRepository.GetAsync(id, includeDetails: true);
return ObjectMapper.Map<Author, AuthorDto>(author);
}
}
From https://docs.abp.io/en/abp/latest/Best-Practices/Entity-Framework-Core-Integration:
Do create a IncludeDetails extension method for the IQueryable<TEntity> for each aggregate root which has sub collections.
...
Do override WithDetails method of the repository for aggregates root which have sub collections.
public static class AuthorEfCoreQueryableExtensions
{
public static IQueryable<Author> IncludeDetails(this IQueryable<Author> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.Films);
}
}
public class AuthorRepository : EfCoreRepository<IMyDbContext, Author, Guid>, IAuthorRepository
{
...
public override IQueryable<Author> WithDetails()
{
return GetQueryable().IncludeDetails(); // Uses the extension method defined above
}
}

How to Properly use Custom Class Generics

I am trying to use Custom Generic class and interface.Im having problems to find a solution for the logic and code of my small Project.
THE BLUEPRINT INTERFACE
public interface IDepartment<T>
{
T CreateAndGetValues(SqlDataReader dataReader);
}
THE POSSIBLE DTO
public class Bank<T> : IDepartment<T>
{
public int LfdNr { get; set; }
public string Kennung { get; set; }
public string Name { get; set; }
public string Straße { get; set; }
public string PLZ { get; set; }
public string Ort { get; set; }
public DateTime TSCREATE { get; set; }
public DateTime TSUPDATE { get; set; }
public T CreateAndGetValues(SqlDataReader dataReader)
{
Bank<T> TheReturnObject = new Bank<T>();
ThereturnObject.LfdNr = Convert.ToInt32(dataReader.GetValue(0));
ThereturnObject.Kennung = dataReader.GetValue(1).ToString();
ThereturnObject.Name = dataReader.GetValue(2).ToString();
ThereturnObject.Straße = dataReader.GetValue(3).ToString();
ThereturnObject.PLZ = dataReader.GetValue(4).ToString();
ThereturnObject.Ort = dataReader.GetValue(5).ToString();
ThereturnObject.TSCREATE = DateTime.ParseExact(dataReader.GetValue(6).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
ThereturnObject.TSUPDATE = DateTime.ParseExact(dataReader.GetValue(7).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
return TheReturnObject;
}
}
THE GENERAL DATABASE READER.
public class Mssql<T> where T :class, IDepartment<T>, new()
{
public List<T> ReadTable()
{
string sqlcommand = "Select * from Bank; ";
List<T> TheListofObject = new List<T>();
using (SqlConnection cnn = new SqlConnection(connetionString))
{
cnn.Open();
using (SqlCommand command = new SqlCommand(sqlcommand, cnn))
{
SqlDataReader dataReader;
try
{
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
IDepartment<T> Object = new T();
Object.CreateAndGetValues(dataReader);
TheListofObject.Add(Object);
}
return TheListofObject;
}
catch (Exception ex)
{
throw;
}
dataReader.Close();
}
cnn.Close();
}
}
}
THE MAIN PROGRAM
class Program
{
static void Main(string[] args)
{
Mssql<Bank<T>> TEST = new Mssql<Bank<T>>();
List<Bank<T>> TheList = TEST.ReadTable();
Console.ReadLine();
}
}
I am expecting that i can use a interface with a method where classes can inherit and return a new type of itself with the Type T and to pass the Type. So that the classes are not dependent that much to each other. And code can be reusable. I hope that is not confusing. Thanks
For this task I strongly recommend using an ORM. They are popular and mostly free. Stackoveflow runs on one of them.
Wikipedia's List of object-relational mapping software gives 9 .NET examples as of Oct 2019.
Here is an example from Dapper's doco.
public class Dog
{
public int? Age { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public float? Weight { get; set; }
public int IgnoredProperty { get { return 1; } }
}
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = #Age, Id = #Id", new { Age = (int?)null, Id = guid });
If you add Dapper.Contrib you don't even need to write the query if you want all records.
public class Car
{
public int Id { get; set; } // Works by convention
public string Name { get; set; }
}
(...)
var cars = connection.GetAll<Car>();
Thank You for your time guys.
I have found an answer with out using any tool to my Problem. And I would like to share it.
//THE BLUEPRINT INTERFACE
public interface IDepartment
{
Object GetAndReadValues(SqlDataReader dataReader);
}
// The Possible DTO
public class Bank : IDepartment
{
public int LfdNr { get; set; }
public string Kennung { get; set; }
public string Name { get; set; }
public string Straße { get; set; }
public string PLZ { get; set; }
public string Ort { get; set; }
public DateTime TSCREATE { get; set; }
public DateTime TSUPDATE { get; set; }
public void CreateAndGetValues(SqlDataReader dataReader)
{
}
public Object GetAndReadValues(SqlDataReader dataReader)
{
Bank ThereturnObject = new Bank();
ThereturnObject.LfdNr = Convert.ToInt32(dataReader.GetValue(0));
ThereturnObject.Kennung = dataReader.GetValue(1).ToString();
ThereturnObject.Name = dataReader.GetValue(2).ToString();
ThereturnObject.Straße = dataReader.GetValue(3).ToString();
ThereturnObject.PLZ = dataReader.GetValue(4).ToString();
ThereturnObject.Ort = dataReader.GetValue(5).ToString();
ThereturnObject.TSCREATE = DateTime.ParseExact(dataReader.GetValue(6).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
ThereturnObject.TSUPDATE = DateTime.ParseExact(dataReader.GetValue(7).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
return ThereturnObject;
}
//THE GENERAL DATABASE READER.
public class Mssql<T> where T :class, IDepartment, new()
{
public List<T> ReadTable()
{
string sqlcommand = "Select * from Bank; ";
List<T> TheListofObject = new List<T>();
using (SqlConnection cnn = new SqlConnection(connetionString))
{
cnn.Open();
using (SqlCommand command = new SqlCommand(sqlcommand, cnn))
{
SqlDataReader dataReader;
try
{
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
IDepartment Object = new T();
object ReturnObject = Object.GetAndReadValues(dataReader);
TheListofObject.Add((T)ReturnObject);
}
return TheListofObject;
}
//Error handling with th DB must be handeld correctly with the specific error
catch (Exception ex)
{
throw;
}
dataReader.Close();
}
cnn.Close();
}
}
}
//THE MAIN PROGRAM
class Program
{
static void Main(string[] args)
{
Mssql<Bank> TEST = new Mssql<Bank>();
List<Bank> TheList = TEST.ReadTable();
foreach (var item in TheList)
{
Console.WriteLine(item.LfdNr);
Console.WriteLine(item.Kennung);
Console.WriteLine(item.Name);
Console.WriteLine(item.Ort);
Console.WriteLine(item.PLZ);
Console.WriteLine(item.Straße);
Console.WriteLine(item.TSCREATE);
Console.WriteLine(item.TSUPDATE);
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
}
Console.ReadLine();
}
}

How to include a new item in the array of items in an object in MongoDB with C #?

How to include a new item in the array of items in an object in MongoDB with C#?
I tried to use the AddToSet method, but I did not succeed.
I have the following code structure:
1 - Parent object (Revenda):
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;
namespace api.mstiDFE.Entidade.api.mstiDFE
{
public class Revenda : Notificavel, IEntidade
{
public Revenda(string Id, long Codigo, string CPF, string CNPJ, List<RevendaCliente> Clientes)
{
this.Id = Id;
this.Codigo = Codigo;
this.CPF = CPF;
this.CNPJ = CNPJ;
this.Clientes = Clientes;
}
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; private set; }
[BsonElement("Codigo")]
public long Codigo { get; private set; }
[BsonElement("Nome")]
public string Nome { get; private set; }
[BsonElement("CPF")]
public string CPF { get; private set; }
[BsonElement("CNPJ")]
public string CNPJ { get; private set; }
[BsonElement("Clientes")]
public ICollection<RevendaCliente> Clientes { get; private set; }
}
}
2 - Child object (RevendaCliente):
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;
namespace api.mstiDFE.Entidade.api.mstiDFE
{
public class RevendaCliente : Notificavel, IEntidade
{
public RevendaCliente(string Codigo, string Nome, string CPF, string CNPJ, ICollection<RevendaClienteToken> Tokens)
{
this.Codigo = Codigo;
this.Nome = Nome;
this.CPF = CPF;
this.CNPJ = CNPJ;
this.Tokens = Tokens;
}
[BsonElement("Codigo")]
public string Codigo { get; private set; }
[BsonElement("Nome")]
public string Nome { get; private set; }
[BsonElement("CPF")]
public string CPF { get; private set; }
[BsonElement("CNPJ")]
public string CNPJ { get; private set; }
[BsonElement("Tokens")]
public ICollection<RevendaClienteToken> Tokens { get; private set; }
}
}
3 - Code used to insert a complete parent object:
public Revenda Add(Revenda revenda)
{
Database.GetCollection<Revenda>("Revendas").InsertOne(revenda);
return revenda;
}
4 - Code used to recover a specific reseller:
public Revenda FindById(string id)
{
return CollRevendas.Find<Revenda>(revenda => revenda.Id == id).FirstOrDefault();
}
Everything works fine.
However, how can I only include a new child object (RevendaCliente) in a parent object (Revenda) already registered in MongoDB?
I am using the following environment:
-Microsoft.AspNetCore.App (2.1.1)
-MongoDB.Driver (2.8.0)
(as I mentioned in my comment) your problem seems pretty simple, as in MongoDB the related objects in hierarchy are part of the same document, so you need to update your object in-memory and update it.
var parentObject=CollRevendas.Find<Revenda>(revenda => revenda.Id == id).FirstOrDefault();
parentObject.Clientes.Add(newChildObject);
//now update the parent object
Code that worked for me: (Resolved with the support of Aarif)
public bool AddRevendaCliente(string revendaId, RevendaCliente requestRevendaClient)
{
try
{
var filter = Builders<Revenda>.Filter.Eq(s => s.Id, revendaId);
// Get a reference to the parent parent "Revenda"
var parentObject = CollRevendas.Find<Revenda>(filter).FirstOrDefault();
parentObject.Clientes.Add(requestRevendaClient);
// Update the parent object "Revenda"
var result = CollRevendas.ReplaceOneAsync(filter, parentObject);
}
catch (Exception ex)
{
throw;
}
return true;
}

Categories