WEB API Entity-Framework Parent Child Posting to SQL Database - entity-framework

I am writing my first WEB-API service based on data that a 3rd party will be sending. Below is the layout they will be sending:
<StandardTitleOrderRequest>
<Authentication>
<UserName>{$USERNAME}</UserName>
<Password>{$PASSWORD}</Password>
</Authentication>
<Borrowers>
<Borrower>
<FirstName>{$BORROWER_FIRST_NAME}</FirstName>
<MiddleName>{$BORROWER_MIDDLE_NAME}</MiddleName>
<LastName>{$BORROWER_LAST_NAME}</LastName>
<SSN>{$BORROWER_SSN}</SSN>
</Borrower>
</Borrowers>-
<Property>
<Address>{$SUBJECT_ADDRESS_STREET}</Address>
<City>{$SUBJECT_ADDRESS_CITY}</City>
<State>{$SUBJECT_ADDRESS_STATE}</State>
<Zip>{$SUBJECT_ADDRESS_ZIP}</Zip>
<County>{$SUBJECT_ADDRESS_COUNTY}</County>
</Property>-
<Contact>
<Name>{$CONTACT_NAME}</Name>
<Phone>{$CONTACT_PHONE}</Phone>
<Fax>{$CONTACT_FAX}</Fax>
<Email>{$CONTACT_EMAIL}</Email>
</Contact>-
<OrderInfo>
<LoanNumber>{$LOAN_NUMBER}</LoanNumber>
<LoanAmount>{$LOAN_AMOUNT}</LoanAmount>
<ToBeInsured/>
<FileNumber>{$FileID}</FileNumber>
<OrderId>{$ORDER_ID}</OrderId >
<CostCenter>{$BRANCH_NAME}</CostCenter>
<Product>{$PRODUCT_NUMBER}</Product>
<Notes>{$ORDER_NOTES}</Notes>
<ResponseURL>{$RESPONSE_URL}</ResponseURL>
<PID></PID>
<PayOffLoanNumber></PayOffLoanNumber>
<ClientCode>{$CLIENT_ID}</ClientCode>
</OrderInfo>
I have created a database with the following 4 tables (Orders, Borrowers, Contacts, Properties) the OrderID is common to each table. The order will have multiple borrowers and 1 contact and 1 property. I have a basic web api built that (using Fiddler) will allow me to GET/POST/PUT/DELETE an order or contact or borrower or property. I am not sure how to add the logic that posts the order and then each of the child elements for that order (borrower(s), contact, property). I am using VS 2017 and EF 6.
I am assuming (perhaps wrongly) that I need to add foreign keys to my tables that reference back to each other and then update the data model but when I do that I start to get various errors.
The 3rd party will be posting 1 transaction at a time so the incoming data will not be in bulk and will be transmitted as XML.
I have tried looking at various tutorials on the whole web api service but 90% of them just deal with a single table POST. Nothing really that goes into specific details about receiving XML data and posting to a parent and 1 or more children. Plus my app will currently only accept the incoming data in JSON format. Below is the code in the OrdersController that will be the basis for the post to the database (POST https://localhost:xxxx/api/Orders)am looking for some direction.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using OrdersDataAccess;
namespace waEtitle.Controllers
{
public class OrdersController : ApiController
{
/// <summary>
/// Get Order Information
/// </summary>
/// <returns></returns>
///
public IEnumerable<Order> Get()
{
using (FirstCloseEntities entities = new FirstCloseEntities())
{
return entities.Orders.ToList();
}
}
public HttpResponseMessage Get(int id)
{
using (FirstCloseEntities entities = new FirstCloseEntities())
{
var entity = entities.Orders.FirstOrDefault(o => o.OrderID == id);
if (entity != null)
{
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Order with id = " + id.ToString() + " not found.");
}
}
}
public HttpResponseMessage Post([FromBody] Order order)
{
try
{
using (FirstCloseEntities entities = new FirstCloseEntities())
{
entities.Orders.Add(order);
entities.SaveChanges();
var message = Request.CreateResponse(HttpStatusCode.Created, order);
message.Headers.Location = new Uri(Request.RequestUri + order.OrderID.ToString());
return message;
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
public HttpResponseMessage Delete(int ID)
{
try
{
using (FirstCloseEntities entities = new FirstCloseEntities())
{
var entity = entities.Orders.FirstOrDefault(c => c.OrderID == ID);
if (entity == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Order with ID = " + ID.ToString() + " not found to delete.");
}
else
{
entities.Orders.Remove(entity);
entities.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK);
}
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
public HttpResponseMessage Put(int id, [FromBody]Order order)
{
try
{
using (FirstCloseEntities entities = new FirstCloseEntities())
{
var entity = entities.Orders.FirstOrDefault(c => c.OrderID== id);
if (entity == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Order with Id = " + id.ToString() + " not found to update.");
}
else
{
entity.LoanNumber = order.LoanNumber;
entity.LoanAmount = order.LoanAmount;
entity.ToBeInsured = order.ToBeInsured;
entity.FileNumber = order.FileNumber;
entity.CostCenter = order.CostCenter;
entity.Product = order.Product;
entity.Notes = order.Notes;
entity.ResponseURL = order.ResponseURL;
entity.PID = order.PID;
entity.PayOffLoanNumber = order.PayOffLoanNumber;
entity.ClientCode = order.ClientCode;
entities.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
}
}
Tables:
/* ==Scripting Parameters==
Source Server Version : SQL Server 2008 R2 (10.50.1617)
Source Database Engine Edition : Microsoft SQL Server Enterprise Edition
Source Database Engine Type : Standalone SQL Server
Target Server Version : SQL Server 2017
Target Database Engine Edition : Microsoft SQL Server Standard Edition
Target Database Engine Type : Standalone SQL Server
*/
USE [FirstCloseAPI]
GO
/****** Object: Table [dbo].[Borrowers] Script Date: 9/26/2017 1:50:18 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Borrowers](
[borID] [int] IDENTITY(1,1) NOT NULL,
[OrderID] [int] NULL,
[FirstName] [varchar](max) NULL,
[MiddleName] [varchar](max) NULL,
[LastName] [varchar](max) NULL,
[SSN] [varchar](max) NULL,
CONSTRAINT [PK_Borrowers] PRIMARY KEY CLUSTERED
(
[borID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object: Table [dbo].[Contacts] Script Date: 9/26/2017 1:50:18 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Contacts](
[conId] [int] IDENTITY(1,1) NOT NULL,
[OrderID] [int] NULL,
[Name] [varchar](max) NULL,
[Phone] [varchar](max) NULL,
[Fax] [varchar](max) NULL,
[Email] [varchar](max) NULL,
CONSTRAINT [PK_Contacts] PRIMARY KEY CLUSTERED
(
[conId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object: Table [dbo].[Orders] Script Date: 9/26/2017 1:50:18 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Orders](
[OrderID] [int] NOT NULL,
[LoanNumber] [varchar](max) NULL,
[LoanAmount] [money] NULL,
[ToBeInsured] [bit] NULL,
[FileNumber] [varchar](max) NULL,
[CostCenter] [varchar](max) NULL,
[Product] [varchar](max) NULL,
[Notes] [varchar](max) NULL,
[ResponseURL] [varchar](max) NULL,
[PID] [int] NULL,
[PayOffLoanNumber] [varchar](max) NULL,
[ClientCode] [varchar](max) NULL,
CONSTRAINT [PK_OrderHeader] PRIMARY KEY CLUSTERED
(
[OrderID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object: Table [dbo].[Properties] Script Date: 9/26/2017 1:50:18 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Properties](
[proID] [int] IDENTITY(1,1) NOT NULL,
[OrderID] [int] NULL,
[Address] [varchar](max) NULL,
[City] [varchar](max) NULL,
[State] [varchar](max) NULL,
[Zip] [varchar](max) NULL,
[County] [varchar](max) NULL,
CONSTRAINT [PK_Property] PRIMARY KEY CLUSTERED
(
[proID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[Borrowers] WITH NOCHECK ADD CONSTRAINT [FK_Borrowers_Orders] FOREIGN KEY([OrderID])
REFERENCES [dbo].[Orders] ([OrderID])
GO
ALTER TABLE [dbo].[Borrowers] NOCHECK CONSTRAINT [FK_Borrowers_Orders]
GO
ALTER TABLE [dbo].[Contacts] WITH NOCHECK ADD CONSTRAINT [FK_Contacts_Orders] FOREIGN KEY([OrderID])
REFERENCES [dbo].[Orders] ([OrderID])
GO
ALTER TABLE [dbo].[Contacts] NOCHECK CONSTRAINT [FK_Contacts_Orders]
GO
ALTER TABLE [dbo].[Properties] WITH NOCHECK ADD CONSTRAINT [FK_Properties_Orders] FOREIGN KEY([OrderID])
REFERENCES [dbo].[Orders] ([OrderID])
GO
ALTER TABLE [dbo].[Properties] NOCHECK CONSTRAINT [FK_Properties_Orders]
GO
Currently my GET is returning
<Order>
<Borrowers />
<ClientCode>cc1</ClientCode>
<Contacts />
<CostCenter>900-111</CostCenter>
<FileNumber>11111</FileNumber>
<LoanAmount>1111.0000</LoanAmount>
<LoanNumber>111</LoanNumber>
<Notes>notes1</Notes>
<OrderID>1</OrderID>
<PID>1</PID>
<PayOffLoanNumber>po1</PayOffLoanNumber>
<Product>letter</Product>
<Properties />
<ResponseURL>yahoo.com</ResponseURL>
<ToBeInsured>true</ToBeInsured>
</Order>
and as you can see there are no contacts or borrowers etc.
**
UPDATE: ---------------------------------------------------
**
I was able to get my Get and GET (int ID) commands to work and return the correct data by changing the procedures as:
public IEnumerable<Order> Get()
{
using (FirstCloseAPIEntities entities = new FirstCloseAPIEntities())
{
var entity = entities.Orders.ToList();
List<Borrower> borrowers = entities.Borrowers.ToList();
List<Contact> contacts = entities.Contacts.ToList();
List<Property> properties = entities.Properties.ToList();
//return entities.Orders.ToList() ;
return entity;
}
}
public HttpResponseMessage Get(int id)
{
using (FirstCloseAPIEntities entities = new FirstCloseAPIEntities())
{
var entity = entities.Orders.FirstOrDefault(o => o.OrderID == id);
List<Borrower> borrowers = entities.Borrowers.Where(b => b.OrderID == id).ToList();
List<Contact> contacts = entities.Contacts.Where(c => c.OrderID == id).ToList();
List<Property> properties = entities.Properties.Where(p => p.OrderID == id).ToList();
if (entity != null)
{
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Order with id = " + id.ToString() + " not found.");
}
}
}
However, because I am requesting as HTML I then was getting the error:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'
So I had to add the following to the Global.asax.cs file:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
This gave me back a successful response, however, no matter what I put in the headers for type application/xml application/json I am always getting the reponse back as JSON.
Content-Type: application/xml
accept: application/xml
accept-encoding: gzip, deflate
accept-language: en-US,en;q=0.8
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Cache-Control: no-cache
Content-Length: 707
Content-Type: application/json; charset=utf-8
Date: Tue, 26 Sep 2017 19:46:42 GMT
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Aspnet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-Sourcefiles: =?UTF-8?B?YzpcdXNlcnNcZG91Zy5oYW1pbHRvblxkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDE3XFByb2plY3RzXHdzRXRpdGxlXHdzRXRpdGxlXGFwaVxPcmRlcnNcMQ==?=
Raw
JSON
{
"OrderID": 1,
"LoanNumber": "111",
"LoanAmount": 1111,
"ToBeInsured": true,
"FileNumber": "11111",
"CostCenter": "900-111",
"Product": "letter",
"Notes": "notes1",
"ResponseURL": "yahoo.com",
"PID": 1,
"PayOffLoanNumber": "po1",
"ClientCode": "cc1",
"Borrowers": [
{
"borID": 1,
"OrderID": 1,
"FirstName": "Ura",
"MiddleName": "O",
"LastName": "Pepper",
"SSN": "111-11-1111"
},
{
"borID": 3,
"OrderID": 1,
"FirstName": "Ima",
"MiddleName": "J",
"LastName": "Pepper",
"SSN": "222-22-2222"
}
],
"Contacts": [
{
"conId": 1,
"OrderID": 1,
"Name": "Jackie the box",
"Phone": "414-555-1243",
"Fax": "414-222-1245",
"Email": "j#test.com"
}
],
"Properties": [
{
"proID": 1,
"OrderID": 1,
"Address": "123 Main Street",
"City": "Anytown",
"State": "WI",
"Zip": "10012
"County": "Westchester"
}
],
}
So I am still confused as to how to get the response in XML and then the last part is to be able to take the information that will be supplied as shown at the top of this post and POST it to the correct tables.

My code changes in the "UPDATED" remarks of my original post allowed me to GET and POST by JSON data to the web api I created on the local host so I was able to work through my issue.
My current additional issues are related to POSTing the data as XML instead of JSON and being able to move the web api to an already existing public facing website. I will post those as separate questions.

Related

Flask PyMongo find_one() return None even when data exists

I just started using MongoDb and I am stuck when using find_one(). The find() function works perfectly but None type is returned when using find_one(). I am stuck at this point. Below is the code that I am using.
#mongo.py
#app.route('/update_user/<emp_id>', methods=['GET', 'POST'])
def update_user(emp_id):
print("Employee ID:", emp_id)
output = list(emp.find_one({'emp_id': emp_id}))
print("Output:", output)
if request.method == 'POST':
if not request.form.get['emp_id'] or not request.form.get['first_name'] or not request.form.get['last_name'] \
or not request.form.get['dept_name'] or not request.form.get['gender'] or not request.form.get['dob'] \
or not request.form.get['salary'] or not request.form['country_code'] \
or not request.form.get['mobile_no']:
flash('Please enter all the fields', 'error')
else:
emp_id = int(request.form.get('emp_id'))
first_name = request.form.get('first_name')
last_name = request.form.get('last_name')
dept_name = request.form.get('dept_name')
gender = request.form.get('gender')
dob = request.form.get('dob')
salary = float(request.form.get('salary'))
country_code = int(request.form['country_code'])
mobile_no = int(request.form.get('mobile_no'))
emp.update_one({"emp_id": emp_id, "first_name": first_name, "last_name": last_name,
"dept_name": dept_name, "gender": gender, "dob": dob, "salary": salary,
"country_code": country_code, "mobile_no": mobile_no})
flash('Employee Updated')
return redirect('user.html')
return render_template('update_user.html', emp_id=emp_id, output=output)
It throws the below error:
File "D:\projects\EmpMgmtFlask\mongo.py", line 37, in update_user
output = list(emp.find_one({'emp_id': emp_id}))
TypeError: 'NoneType' object is not iterable
find_one() doesn't return a cursor; it returns a single dictionary; so you don't need to wrap it in a list function.
output = emp.find_one({'emp_id': emp_id})

Spring data r2dbc and group by

I am using the DatabaseClient to perform my sql queries and I don't see how I can do a group by:
databaseClient.select()
.from( myClass.class )
.matching( where( "row_1" ).is( "value_1" ) )
//group by row_2 ...
.orderBy( Sort.Order.desc( "row_3" ) )
.page( pageable )
.fetch()
.all();
A workaround solution using sql directly.
public Flux<Map<Object, Object>> countByStatus() {
return this.databaseClient
.sql("SELECT count(*) as cnt, status FROM posts group by status")
.map((row, rowMetadata) -> {
Long cnt = row.get("cnt", Long.class);
Post.Status s = row.get("status", Post.Status.class);
return Map.<Object, Object>of("cnt", cnt, "status", s);
})
.all();
}
Check the complete codes.

Record data from get request to table in apex oracle

i need help with apex oracle. This task is not typical for me, so I ask for help. I have a rest point (get). As a result, I have the answer:
{
"DT_СREATE": "2020-02-05T10:38:11Z",
"DT_UPDATE": "2020-02-05T10:38:11Z",
"ID": 12015,
"sensors": [
{
"name": "SENSOR1",
"temp": "11.91"
},
{
"name": "SENSOR2",
"temp": "9.23"
}
]
}
I also have a TEMPR_SILO table. In which I want to write this answer!
CREATE TABLE "TEMPR_SILO"
( "ID" NUMBER,
"NAME" VARCHAR2(500),
"TEMP" VARCHAR2(500),
"ID_TRANS" NUMBER,
CONSTRAINT "TEMPR_SILO_PK" PRIMARY KEY ("ID")
USING INDEX ENABLE
)
/
but all this should be the result of a dynamic action after pushing a button on the weed. That is, when the button is pressed, I have to record the data from the GET.
I wrote a POST for this. here he is.
BEGIN
v_clob := iot_general.blob_to_clob(p_blob);
apex_json.parse(tv, v_clob);
v_id := apex_json.get_varchar2(p_path => 'id', p_values => tv);
sCount := APEX_JSON.get_count(p_path => 'sensors' , p_values => tv);
IF sCount > 0 THEN
FOR i in 1 .. sCount LOOP
q_temp := apex_json.get_varchar2(p_path => 'sensors['|| i ||'].temp', p_values => tv);
q_name := apex_json.get_varchar2(p_path => 'sensors['|| i ||'].name', p_values => tv);
INSERT INTO TEMPR_SILO ( NAME, TEMP,ID_TRANS)
VALUES ( q_name , q_temp ,v_id);
commit;
END LOOP;
END IF;
But I don't know how to use it in my task! I would appreciate an example or help in this question!
If you have validated that your last snippet is working, it's just a matter of creating the Dynamic Action on the button, with a PL/SQL code true action and putting it there. If you want to follow best practices, you would have that code in a procedure on the DB, and that's what you would call in the DA.

Can't add a claim with ASP.NET Core and identity

I try to add a custom claim to an existing Identity user but I get an exception at run-time:
Npgsql.PostgresException: 23502: null value in column "Id" violates not-null constraint
Help!
What I did. I've created a simple web app on windows using the following command line
dotnet new mvc --auth Individual --framework netcoreapp1.1
I made changes found here to make the app use PostgreSQL as the database back-end. The created default webapp works fine. I can register as a new user, login, log out, etc...
Then I modified the Test method of the Home controller (I know the exceptions are ugly):
[Authorize]
public async Task<IActionResult> Test()
{
var user = await GetCurrentUserAsync();
if (user == null) {
_logger.LogWarning("User is null.");
throw new Exception("Not logged in");
}
_logger.LogWarning("User: {0}, {1}", user.Email, user);
var claim = new Claim("TestClaimType", "TestClaimValue");
IdentityResult idRes = IdentityResult.Failed();
if (_userManager.SupportsUserClaim) {
idRes = await _userManager.AddClaimAsync(user, claim); <------- Adding the claim
}
_logger.LogWarning("Return from adding claim");
if (idRes != IdentityResult.Success) {
throw new Exception("Failed to add claim.");
}
return View();
}
After logging in, I trigger the Test method and get the following logging (the PostgresException is near the end):
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/Home/Test
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware[3]
HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Identity.Application.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
Authorization was successful for user: mark#mark.com.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method AlumniConnect.Controllers.HomeController.Test (AlumniConnect) with arguments ((null)) - ModelState is Valid
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1]
Executed DbCommand (1ms) [Parameters=[#__get_Item_0='?'], CommandType='Text', CommandTimeout='30']
SELECT "e"."Id", "e"."AccessFailedCount", "e"."ConcurrencyStamp", "e"."Email", "e"."EmailConfirmed", "e"."LockoutEnabled", "e"."LockoutEnd", "e"."NormalizedEmail", "e"."NormalizedUserName", "e"."PasswordHash", "e"."PhoneNumber", "e"."PhoneNumberConfirmed", "e"."SecurityStamp", "e"."TwoFactorEnabled", "e"."UserName"
FROM "AspNetUsers" AS "e"
WHERE "e"."Id" = #__get_Item_0
LIMIT 1
warn: AlumniConnect.Controllers.HomeController[0]
User: mark#mark.com, mark#mark.com
warn: AlumniConnect.Controllers.HomeController[0]
User: mark#mark.com, mark#mark.com
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1]
Executed DbCommand (4ms) [Parameters=[#__normalizedUserName_0='?'], CommandType='Text', CommandTimeout='30']
SELECT "u"."Id", "u"."AccessFailedCount", "u"."ConcurrencyStamp", "u"."Email", "u"."EmailConfirmed", "u"."LockoutEnabled", "u"."LockoutEnd", "u"."NormalizedEmail", "u"."NormalizedUserName", "u"."PasswordHash", "u"."PhoneNumber", "u"."PhoneNumberConfirmed", "u"."SecurityStamp", "u"."TwoFactorEnabled", "u"."UserName"
FROM "AspNetUsers" AS "u"
WHERE "u"."NormalizedUserName" = #__normalizedUserName_0
LIMIT 1
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1]
Executed DbCommand (33ms) [Parameters=[#p0='?', #p1='?', #p2='?', #p17='?', #p3='?', #p4='?', #p18='?', #p5='?', #p6='?', #p7='?', #p8='?', #p9='?', #p10='?', #p11='?', #p12='?', #p13='?', #p14='?', #p15='?', #p16='?'], CommandType='Text', CommandTimeout='30']
INSERT INTO "AspNetUserClaims" ("ClaimType", "ClaimValue", "UserId")
VALUES (#p0, #p1, #p2)
RETURNING "Id";
UPDATE "AspNetUsers" SET "AccessFailedCount" = #p3, "ConcurrencyStamp" = #p4, "Email" = #p5, "EmailConfirmed" = #p6, "LockoutEnabled" = #p7, "LockoutEnd" = #p8, "NormalizedEmail" = #p9, "NormalizedUserName" = #p10, "PasswordHash" = #p11, "PhoneNumber" = #p12, "PhoneNumberConfirmed" = #p13, "SecurityStamp" = #p14, "TwoFactorEnabled" = #p15, "UserName" = #p16
WHERE "Id" = #p17 AND "ConcurrencyStamp" = #p18;
fail: Microsoft.EntityFrameworkCore.DbContext[1]
An exception occurred in the database while saving changes.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Npgsql.PostgresException: 23502: null value in column "Id" violates not-null constraint
at Npgsql.NpgsqlConnector.<DoReadMessageAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
There's lots of logging more but it doesn't seem to add new information. I see the same exception mentioned multiple times throughout the log.
What can I do? Is this a PostgreSQL specific issue? Am I trying to add a claim in the wrong way?
Thanks!
In the migration for Identity, all tables that have a generated Integer id have an annotation for adding auto generation of this id. This annotation is SQL Server specific, like .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
The fix for this is to add a Postgres specific annotation to the migration: .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn). In older versions of Npgsql.EntityFrameworkCore.PostgreSQL it could be that you need to use .Annotation("Npgsql:ValueGeneratedOnAdd", true).
The part of the migration for creating the AspNetRoleClaims table will then look like:
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true),
RoleId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
It appears that when the Claim is added to the database, the 'RETURNING "Id"' clause of the SQL statement suggests the ID is returned. However, the table does not have an auto incrementing ID column.
I verified this by following the instructions from Adding 'serial' to existing column in Postgres.
The problem is now of course that this should have been taken care of automatically...

First wordpress plugin making

I am making my very first wordpress plugin in that I want to make table in my database when I activate the plugin. I write the code exactly what wordpress community said but it's not working. I tried the same several times but the results is the same. I also want to know my plugin showing 2 submenus in my main plugin menu, It's like
My Plugin
-- My Plugin
-- My Submenu Page
Please help I am very new to plugin development.
// Registering plugin
register_activation_hook(__FILE__, 'myplugin_activate');
//Deactivate plugin
register_deactivation_hook(__FILE__, 'myplugin_deactivate');
function myplugin_activate() {
global $wpdb, $table_prefix;
global $favoritethis_db_version;
$table_name = $table_prefix.
'my-plugin-table';
$charset_collate = $wpdb - > get_charset_collate();
if ($wpdb - > get_var("show tables like '$table_name'") != $table_name) {
require_once(ABSPATH.
'wp-admin/upgrade-functions.php');
$sql = "CREATE TABLE ".$table_name.
" (
id mediumint(9) NOT NULL AUTO_INCREMENT,
time datetime DEFAULT '0000-00-00 00:00:00'
NOT NULL,
name tinytext NOT NULL,
text text NOT NULL,
url varchar(55) DEFAULT ''
NOT NULL,
UNIQUE KEY id(id)
) $charset_collate;
";
}
require_once(ABSPATH.
'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
function myplugin_deactivate() {
// Deactivation code here...
echo "<script>alert('Ohhh.. no baby the plugin is deactivated now..')</script>";
}
also I found the solution of the problem, I was facing as getting extra sub menu as same name as the main menu is.
Solution
//Main admin menus
add_action('admin_menu', 'add_my_custom_menu');
function add_my_custom_menu() {
//add an item to the menu
add_menu_page(
'My Plugin',
'My Plugin',
10,
plugin_dir_path(__FILE__).
'admin/plugin-form.php',
'',
plugin_dir_url(__FILE__).
'img/contact.png'
);
add_submenu_page(
'my-plugin-name/admin/plugin-form.php',
'Plugin Setting',
'Plugin Setting',
10,
plugin_dir_path(__FILE__).
'admin/plugin-form.php',
'myplugin_options_page'
);
add_submenu_page(
'my-plugin-name/admin/plugin-form.php',
'Plugin Entries',
'Plugin Entries',
10,
plugin_dir_path(__FILE__).
'admin/entries.php',
''
);
}
reason is that every first sub-menu's destination page/function will be the same as main menu destination.
ok I got the answer myself
// Registering plugin
register_activation_hook(__FILE__, 'myplugin_activate');
//Deactivate plugin
register_deactivation_hook(__FILE__, 'myplugin_deactivate');
function myplugin_activate() {
global $wpdb;
$table_name = $wpdb - > prefix.
'my-plugin-table';
//nstalled_ver = get_option('my-voting-version');
if ($wpdb - > get_var("show tables like '$table_name' ") != $table_name) {
require_once(ABSPATH.
'wp-admin/upgrade-functions.php');
$sql = "CREATE TABLE IF NOT EXISTS `".str_replace('`', '', $table_name).
"` (
id mediumint(9) NOT NULL AUTO_INCREMENT,
time datetime DEFAULT '0000-00-00 00:00:00'
NOT NULL,
name tinytext NOT NULL,
text text NOT NULL,
url varchar(55) DEFAULT ''
NOT NULL,
UNIQUE KEY id(id)
);
";
}
require_once(ABSPATH.
'wp-admin/includes/upgrade.php');
dbDelta($sql);
}