Partilhar via


Como conectar seu aplicativo de código ao Azure SQL

Este guia explica como configurar um Azure SQL Database e conectá-lo a um aplicativo de código do Power Apps usando a biblioteca de clientes do Power Apps para aplicativos de código.

Este guia aborda:

  • Provisionando um SQL Server do Azure e um banco de dados
  • Criando tabelas SQL e procedimentos armazenados
  • Conectar um aplicativo de código Power Apps usando a biblioteca de clientes Power Apps para aplicativos de código

Pré-requisitos

Configurar o banco de dados e o SQL Server do Azure

  1. Navegue até a opção Selecione a opção de implantação de SQL - Microsoft Azure
  2. Selecionar banco de dados SQL –> Tipo de recurso: banco de dados único ->Criar
  3. Preencher:
    • Grupo de recursos: selecione Criar novo e insira um nome de grupo de recursos, por exemplo, rg-codeapps-dev
    • Nome do banco de dados: sqldb-codeapps-dev
    • Servidor: Selecione Criar novo e Preencher:
      • Nome do servidor: sql-codeapps-dev
      • Local: selecione a região mais próxima do seu ambiente do Power Platform.
      • Método de autenticação: Use somente a autenticação do Microsoft Entra
      • Definir administrador do Microsoft Entra: selecione Definir administrador e, em seguida, selecione seu próprio usuário.
    • Selecione OK
  4. Computação + storage: Uso Geral – Sem servidor
  5. Selecione Avançar: Rede
  6. Preencher:
    • Método de conectividade: ponto de extremidade público
    • Permitir que serviços e recursos do Azure acessem este servidor: Sim
    • Adicionar o endereço IP do cliente atual: Sim
  7. Selecionar Revisão + criar ->Criar
  8. Aguarde até que a Implantação seja concluída e selecione Ir para o recurso

Implantar dados de exemplo

  1. No Visual Studio Code, selecione Extensões (Ctrl + Shift + X)

  2. Localize a extensão SQL Server (mssql) na Barra de Atividades e abra-a ou use Ctrl + Alt + D

  3. Em Conexões, selecione + Adicionar Conexão

    Adicionar Conexão na extensão do SQL Server para VS Code

  4. Na caixa de diálogo Conectar ao Banco de Dados, selecione Browse Azure, selecione sua assinatura, grupo de recursos (por exemplo: rg-codeapps-dev), Servidor (por exemplo: sql-codeapps-dev) e banco de dados (por exemplo, sqldb-codeapps-dev)

  5. Em Tipo de Autenticação, selecione Microsoft Entra ID – Universal com suporte de MFA

  6. Verifique se o Azure portal está aberto no navegador e selecione Sign In. Será solicitado a entrar, e, em seguida, verá:

    Prompt de entrada do Microsoft Entra para conexão SQL

  7. Selecione Connect

    Conectado ao banco de dados SQL do Azure no VS Code

  8. No painel SQL SERVER, clique com o botão direito do mouse no banco de dados e selecione New Query

    Novo comando Consulta para banco de dados na extensão SQL do VS Code

  9. Na nova janela de consulta, cole o seguinte SQL:

    -- Drop existing objects if they exist
    IF OBJECT_ID('dbo.Projects', 'U') IS NOT NULL DROP TABLE dbo.Projects;
    
    -- =============================================
    -- CREATE TABLES
    -- =============================================
    
    -- Projects Table
    CREATE TABLE [dbo].[Projects](
        [ProjectId] [int] IDENTITY(1,1) NOT NULL,
        [Name] [nvarchar](255) NOT NULL,
        [Description] [nvarchar](max) NULL,
        [StartDate] [date] NULL,
        [EndDate] [date] NULL,
        [Status] [nvarchar](50) NOT NULL DEFAULT ('Planning'),
        [Priority] [nvarchar](20) NOT NULL DEFAULT ('Medium'),
        [Budget] [decimal](18, 2) NULL,
        [ProjectManagerEmail] [nvarchar](255) NOT NULL,
        [CreatedBy] [nvarchar](255) NOT NULL,
        [CreatedDate] [datetime2](7) NOT NULL DEFAULT (getutcdate()),
        [IsActive] [bit] NOT NULL DEFAULT (1),
        CONSTRAINT [PK_Projects] PRIMARY KEY ([ProjectId])
    );
    GO
    
    -- =============================================
    -- ADD CONSTRAINTS
    -- =============================================
    
    -- Project Status Check
    ALTER TABLE [dbo].[Projects] ADD CONSTRAINT [CK_Projects_Status] 
    CHECK ([Status] IN ('Planning', 'Active', 'On Hold', 'Completed', 'Cancelled'));
    
    -- Project Priority Check
    ALTER TABLE [dbo].[Projects] ADD CONSTRAINT [CK_Projects_Priority] 
    CHECK ([Priority] IN ('Low', 'Medium', 'High', 'Critical'));
    GO
    
    -- =============================================
    -- STORED PROCEDURES
    -- =============================================
    
    -- Get All Projects
    IF OBJECT_ID('dbo.GetAllProjects', 'P') IS NOT NULL DROP PROCEDURE dbo.GetAllProjects;
    GO
    CREATE PROCEDURE [dbo].[GetAllProjects]
    AS
    BEGIN
        SET NOCOUNT ON;
    
        SELECT 
            [ProjectId], [Name], [Description], [StartDate], [EndDate],
            [Status], [Priority], [Budget], [ProjectManagerEmail],
            [CreatedBy], [CreatedDate], [IsActive]
        FROM [dbo].[Projects]
        WHERE [IsActive] = 1
        ORDER BY [CreatedDate] DESC;
    END
    GO
    
    -- Create Project
    IF OBJECT_ID('dbo.CreateProject', 'P') IS NOT NULL DROP PROCEDURE dbo.CreateProject;
    GO
    CREATE PROCEDURE [dbo].[CreateProject]
        @Name NVARCHAR(255),
        @Description NVARCHAR(MAX) = NULL,
        @StartDate DATE = NULL,
        @EndDate DATE = NULL,
        @Status NVARCHAR(50) = 'Planning',
        @Priority NVARCHAR(20) = 'Medium',
        @Budget DECIMAL(18,2) = NULL,
        @ProjectManagerEmail NVARCHAR(255),
        @CreatedBy NVARCHAR(255)
    AS
    BEGIN
        SET NOCOUNT ON;
    
        INSERT INTO [dbo].[Projects] (
            [Name], [Description], [StartDate], [EndDate], 
            [Status], [Priority], [Budget], [ProjectManagerEmail], [CreatedBy]
        )
        VALUES (
            @Name, @Description, @StartDate, @EndDate,
            @Status, @Priority, @Budget, @ProjectManagerEmail, @CreatedBy
        );
    
        SELECT SCOPE_IDENTITY() as ProjectId;
    END
    GO
    
    -- Update Project
    IF OBJECT_ID('dbo.UpdateProject', 'P') IS NOT NULL DROP PROCEDURE dbo.UpdateProject;
    GO
    CREATE PROCEDURE [dbo].[UpdateProject]
        @ProjectId INT,
        @Name NVARCHAR(255) = NULL,
        @Description NVARCHAR(MAX) = NULL,
        @StartDate DATE = NULL,
        @EndDate DATE = NULL,
        @Status NVARCHAR(50) = NULL,
        @Priority NVARCHAR(20) = NULL,
        @Budget DECIMAL(18,2) = NULL,
        @ProjectManagerEmail NVARCHAR(255) = NULL
    AS
    BEGIN
        SET NOCOUNT ON;
    
        UPDATE [dbo].[Projects]
        SET 
            [Name] = ISNULL(@Name, [Name]),
            [Description] = ISNULL(@Description, [Description]),
            [StartDate] = ISNULL(@StartDate, [StartDate]),
            [EndDate] = ISNULL(@EndDate, [EndDate]),
            [Status] = ISNULL(@Status, [Status]),
            [Priority] = ISNULL(@Priority, [Priority]),
            [Budget] = ISNULL(@Budget, [Budget]),
            [ProjectManagerEmail] = ISNULL(@ProjectManagerEmail, [ProjectManagerEmail])
        WHERE [ProjectId] = @ProjectId AND [IsActive] = 1;
    
        SELECT @@ROWCOUNT as RowsAffected;
    END
    GO
    
    -- Delete Project (Soft Delete)
    IF OBJECT_ID('dbo.DeleteProject', 'P') IS NOT NULL DROP PROCEDURE dbo.DeleteProject;
    GO
    CREATE PROCEDURE [dbo].[DeleteProject]
        @ProjectId INT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        UPDATE [dbo].[Projects]
        SET [IsActive] = 0
        WHERE [ProjectId] = @ProjectId AND [IsActive] = 1;
    
        SELECT @@ROWCOUNT as RowsAffected;
    END
    GO
    
    -- =============================================
    -- SAMPLE DATA
    -- =============================================
    
    -- Insert Sample Projects
    INSERT INTO [dbo].[Projects] ([Name], [Description], [StartDate], [EndDate], [Status], [Priority], [Budget], [ProjectManagerEmail], [CreatedBy]) VALUES
    ('Website Redesign', 'Complete redesign of company website with modern UI/UX', '2025-06-01', '2025-08-31', 'Active', 'High', 75000.00, 'sarah.johnson@company.com', 'admin@company.com'),
    ('Mobile App Development', 'Develop iOS and Android mobile application for customer portal', '2025-07-01', '2025-12-31', 'Planning', 'Critical', 150000.00, 'mike.chen@company.com', 'admin@company.com'),
    ('Database Migration', 'Migrate legacy database to cloud infrastructure', '2025-05-15', '2025-09-30', 'Active', 'Medium', 50000.00, 'lisa.williams@company.com', 'admin@company.com');
    GO
    
    PRINT 'Projects-only database schema created successfully with sample data!';
    
  10. Selecione o botão de execução verde (Ctrl-Shift-E) para executar a consulta.

  11. Você não deve ver erros na saída RESULTADOS DA CONSULTA .

Inicializar seu aplicativo de código

Se você ainda não tiver, crie e/ou inicialize seu aplicativo de código usando as instruções aqui: Crie um aplicativo do zero.

Criar uma conexão SQL Server no Power Platform

  1. Abra Power Apps

  2. Selecione seu ambiente

  3. Navegue até Conexões. Pode estar no ... Mais menu.

  4. Selecionar + Nova Conexão

    + Nova Conexão em Power Apps

  5. Selecione SQL Server

  6. Selecione Tipo de Autenticação: Microsoft Entra ID Integrado

  7. Selecione Criar e faça login no prompt de autenticação exibido

Adicionar conexões de tabela SQL ao seu aplicativo

  1. Liste as conexões disponíveis em seu ambiente. Você deve ver a conexão que criou:

    pac connection list
    

    Você deve ver uma lista semelhante a:

    Lista de conexões do Power Platform mostrando a conexão SQL

  2. Para adicionar a tabela de projetos à project, copie a ID da conexão (a primeira coluna) e use o seguinte comando:

    pac code add-data-source -a "shared_sql" -c "[CONNECTION ID]"  -d "[SQL SERVER NAME].database.windows.net,[DATA BASE NAME]" -sp "dbo.GetAllProjects"
    

    Por exemplo:

    pac code add-data-source -a "shared_sql" -c "aaaa0000bb11222233cc444444dddddd"  -d "sql-codeapps-dev.database.windows.net,sqldb-codeapps-dev" -sp "dbo.GetAllProjects"
    
  3. Abra as pastas Services e Models e observe o código recém-gerado.

Adicionar tabela de projetos

  1. Usamos a interface do usuário fluente para mostrar uma tabela de projetos, portanto, faça downgrade para o React 18 e instale usando:

    npm install react@^18.0.0 react-dom@^18.0.0 @types/react@^18.0.0 @types/react-dom@^18.0.0
    npm install @fluentui/react-components
    
  2. Adicione um novo arquivo em src nome ProjectsTable.tsx com o seguinte código:

    /**
     * ProjectsTable Component - Displays project data from Power Platform in a sortable DataGrid
     */
    import React, { useEffect, useState, useCallback, useMemo } from 'react';
    import {
      DataGrid,
      DataGridHeader,
      DataGridRow,
      DataGridHeaderCell,
      DataGridCell,
      DataGridBody,
      TableColumnDefinition,
      TableRowId,
      Spinner,
      MessageBar,
      Badge,
      makeStyles,
      tokens,
    } from '@fluentui/react-components';
    import { GetAllProjectsService } from './Services/GetAllProjectsService';
    
    // String formatting utility for localizable messages
    const formatMessage = (template: string, params: Record<string, string | number> = {}): string => {
      return template.replace(/\{(\w+)\}/g, (match, key) => {
        const value = params[key];
        return value !== undefined ? String(value) : match;
      });
    };
    
    // Common UI messages
    const MESSAGE_STRINGS = {
      LOADING: 'Loading data...',
      NO_DATA: 'No data found.',
      GENERIC_ERROR: 'An unexpected error occurred',
      LOAD_ERROR: 'Failed to load data. Please try again.',
      PROJECT_COUNTER_SINGLE: 'Showing {count} project',
      PROJECT_COUNTER_PLURAL: 'Showing {count} projects',
      COLUMN_PROJECT_NAME: 'Project Name',
      COLUMN_DESCRIPTION: 'Description',
      COLUMN_START_DATE: 'Start Date',
      COLUMN_END_DATE: 'End Date',
      COLUMN_STATUS: 'Status',
      COLUMN_PRIORITY: 'Priority',
      ARIA_LABEL_DATA_GRID: 'Projects data grid',
    } as const;
    
    // Project data type
    type ProjectItem = {
      ProjectId?: number;
      Name?: string;
      Description?: string;
      StartDate?: string;
      EndDate?: string;
      Status?: string;
      Priority?: string;
      Budget?: number;
      ProjectManagerEmail?: string;
      CreatedBy?: string;
      CreatedDate?: string;
      IsActive?: boolean;
    };
    
    // DataGrid columns
    const COLUMNS: TableColumnDefinition<ProjectItem>[] = [
      {
        columnId: 'name',
        compare: (a, b) => (a.Name || '').localeCompare(b.Name || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_PROJECT_NAME,
        renderCell: (item) => item.Name || '',
      },
      {
        columnId: 'description',
        compare: (a, b) => (a.Description || '').localeCompare(b.Description || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_DESCRIPTION,
        renderCell: (item) => item.Description || '',
      },
      {
        columnId: 'startDate',
        compare: (a, b) => new Date(a.StartDate || '').getTime() - new Date(b.StartDate || '').getTime(),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_START_DATE,
        renderCell: (item) => item.StartDate ? new Date(item.StartDate).toLocaleDateString() : '',
      },
      {
        columnId: 'endDate',
        compare: (a, b) => new Date(a.EndDate || '').getTime() - new Date(b.EndDate || '').getTime(),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_END_DATE,
        renderCell: (item) => item.EndDate ? new Date(item.EndDate).toLocaleDateString() : '',
      }, {
        columnId: 'status',
        compare: (a, b) => (a.Status || '').localeCompare(b.Status || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_STATUS,
        renderCell: (item) => <StatusBadge status={item.Status || ''} />,
      },
      {
        columnId: 'priority',
        compare: (a, b) => (a.Priority || '').localeCompare(b.Priority || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_PRIORITY,
        renderCell: (item) => <PriorityBadge priority={item.Priority || ''} />,
      },
    ];
    
    // Row ID generator
    const getRowId = (item: ProjectItem): TableRowId =>
      item.ProjectId?.toString() || `temp-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
    
    // Extracts a user-friendly error message from various error types
    const extractErrorMessage = (
      error: unknown,
      fallbackMessage = MESSAGE_STRINGS.GENERIC_ERROR
    ): string => {
      if (error instanceof Error) {
        return error.message;
      }
      if (typeof error === 'string') {
        return error;
      } return fallbackMessage;
    };
    
    // Badge component for Priority
    const PriorityBadge: React.FC<{ priority: string }> = React.memo(({ priority }) => {
      const styles = useStyles();
      const badgeProps = useMemo(() => {
        const getPriorityAppearance = (priority: string) => {
          switch (priority?.toLowerCase()) {
            case 'critical':
              return { appearance: 'filled' as const, color: 'danger' as const };
            case 'high':
              return { appearance: 'filled' as const, color: 'important' as const };
            case 'medium':
              return { appearance: 'filled' as const, color: 'warning' as const };
            case 'low':
              return { appearance: 'filled' as const, color: 'success' as const };
            default:
              return { appearance: 'outline' as const, color: 'subtle' as const };
          }
        };
        return getPriorityAppearance(priority);
      }, [priority]);
    
      return (
        <Badge {...badgeProps} className={styles.badge}>
          {priority || 'Unknown'}
        </Badge>
      );
    });
    
    PriorityBadge.displayName = 'PriorityBadge';
    
    // Badge component for Status
    const StatusBadge: React.FC<{ status: string }> = React.memo(({ status }) => {
      const styles = useStyles();
      const badgeProps = useMemo(() => {
        const getStatusAppearance = (status: string) => {
          switch (status?.toLowerCase()) {
            case 'completed':
              return { appearance: 'filled' as const, color: 'success' as const };
            case 'active':
              return { appearance: 'filled' as const, color: 'brand' as const };
            case 'planning':
              return { appearance: 'filled' as const, color: 'informative' as const };
            case 'on hold':
              return { appearance: 'filled' as const, color: 'warning' as const };
            case 'cancelled':
              return { appearance: 'filled' as const, color: 'danger' as const };
            default:
              return { appearance: 'outline' as const, color: 'subtle' as const };
          }
        };
        return getStatusAppearance(status);
      }, [status]);
    
      return (
        <Badge {...badgeProps} className={styles.badge}>
          {status || 'Unknown'}
        </Badge>
      );
    });
    
    StatusBadge.displayName = 'StatusBadge';
    
    // Styles
    const useStyles = makeStyles({
      container: {
        padding: tokens.spacingVerticalXXL,
      },
      loadingContainer: {
        display: 'flex',
        alignItems: 'center',
        gap: tokens.spacingHorizontalS,
        padding: tokens.spacingVerticalXXL,
      },
      messageBar: {
        marginBottom: tokens.spacingVerticalXL,
      },
      projectCounter: {
        marginBottom: tokens.spacingVerticalM,
        fontSize: tokens.fontSizeBase200,
        color: tokens.colorNeutralForeground2,
      }, dataGrid: {
        width: '100%',
      },
      badge: {
        fontSize: tokens.fontSizeBase200,
        fontWeight: tokens.fontWeightMedium,
        textTransform: 'capitalize',
      },
    });
    
    // Custom hook to fetch and manage project data
    const useProjectsData = (): {
      projects: ProjectItem[];
      loading: boolean;
      error: string | null;
      refetch: () => Promise<void>;
    } => {
      const [projects, setProjects] = useState<ProjectItem[]>([]);
      const [loading, setLoading] = useState(true);
      const [error, setError] = useState<string | null>(null);
    
      const fetchProjects = useCallback(async () => {
        try {
          setLoading(true);
          setError(null); const result = await GetAllProjectsService.GetAllProjects();
          if (result.success && result.data?.ResultSets?.Table1) {
            const projectsData = Array.isArray(result.data.ResultSets.Table1)
              ? result.data.ResultSets.Table1 as ProjectItem[]
              : [result.data.ResultSets.Table1] as ProjectItem[];
            setProjects(projectsData);
          } else {
            const errorMsg = result.error instanceof Error
              ? result.error.message
              : result.error || MESSAGE_STRINGS.LOAD_ERROR;
            setError(errorMsg);
            console.error('Failed to fetch projects:', result.error);
          }
        } catch (error) {
          const errorMessage = extractErrorMessage(error, MESSAGE_STRINGS.GENERIC_ERROR);
          setError(errorMessage);
          console.error('Error fetching projects:', error);
        } finally {
          setLoading(false);
        }
      }, []);
    
      useEffect(() => {
        fetchProjects();
      }, [fetchProjects]);
    
      return { projects, loading, error, refetch: fetchProjects };
    };
    
    // UI Components
    const LoadingSpinner: React.FC = () => {
      const styles = useStyles();
      return (
        <div className={styles.loadingContainer}>
          <Spinner size="small" />
          <span>{MESSAGE_STRINGS.LOADING}</span>
        </div>
      );
    };
    
    const ErrorMessage: React.FC<{ error: string }> = ({ error }) => {
      const styles = useStyles();
      return (
        <MessageBar intent="error" className={styles.messageBar}>
          {error}
        </MessageBar>
      );
    };
    
    const EmptyState: React.FC = () => {
      const styles = useStyles();
      return (
        <MessageBar intent="info" className={styles.messageBar} style={{ textAlign: 'center' }}>
          {MESSAGE_STRINGS.NO_DATA}
        </MessageBar>
      );
    };
    
    const ProjectCounter: React.FC<{ count: number }> = ({ count }) => {
      const styles = useStyles();
    
      const counterMessage = useMemo(() => {
        return count === 1
          ? formatMessage(MESSAGE_STRINGS.PROJECT_COUNTER_SINGLE, { count })
          : formatMessage(MESSAGE_STRINGS.PROJECT_COUNTER_PLURAL, { count });
      }, [count]);
    
      return (
        <div className={styles.projectCounter}>
          {counterMessage}
        </div>
      );
    };
    
    // Main component
    const ProjectsTable: React.FC = () => {
      const styles = useStyles();
      const { projects, loading, error } = useProjectsData();
      const projectCount = useMemo(() => projects.length, [projects.length]);
      const memoizedProjects = useMemo(() => projects, [projects]);
      const dataGridProps = useMemo(() => ({
        items: memoizedProjects,
        columns: COLUMNS,
        sortable: true,
        getRowId,
        focusMode: "cell" as const,
        className: styles.dataGrid,
        "aria-label": MESSAGE_STRINGS.ARIA_LABEL_DATA_GRID,
      }), [memoizedProjects, styles.dataGrid]);
    
      if (loading) {
        return (
          <div className={styles.container}>
            <LoadingSpinner />
          </div>
        );
      }
    
      if (error) {
        return (
          <div className={styles.container}>
            <ErrorMessage error={error} />
          </div>
        );
      }
    
      if (projectCount === 0) {
        return (
          <div className={styles.container}>
            <EmptyState />
          </div>
        );
      }
      return (
        <div className={styles.container}>
          <ProjectCounter count={projectCount} />      <DataGrid {...dataGridProps}>
            <DataGridHeader>
              <DataGridRow>
                {({ renderHeaderCell }) => (
                  <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
                )}
              </DataGridRow>
            </DataGridHeader>
            <DataGridBody<ProjectItem>>
              {({ item, rowId }) => (
                <DataGridRow<ProjectItem> key={rowId}>
                  {({ renderCell }) => (
                    <DataGridCell>{renderCell(item)}</DataGridCell>
                  )}
                </DataGridRow>
              )}
            </DataGridBody>
          </DataGrid>
        </div>
      );
    };
    
    export default React.memo(ProjectsTable);
    
    
  3. Adicione o FluentProvider e ProjectsTable para maint.tsx:

     import { StrictMode } from 'react'
     import { createRoot } from 'react-dom/client'
     import './index.css'
     import PowerProvider from './PowerProvider.tsx'
     import { FluentProvider, webLightTheme } from '@fluentui/react-components'
     import ProjectsTable from './ProjectsTable.tsx'
    
     createRoot(document.getElementById('root')!).render(
       <StrictMode>
         <PowerProvider>
           <FluentProvider theme={webLightTheme}>
             <ProjectsTable />
           </FluentProvider>
         </PowerProvider>
       </StrictMode>,
     )
    
    
  4. Execute seu aplicativo usando:

    npm run dev
    

    Na janela de comando que é aberta, abra o link do aplicativo fornecido:

    Biblioteca de clientes para o console de aplicativos de código com a URL e o status do aplicativo

  5. Quando o aplicativo for aberto, você deverá ver uma caixa de diálogo de consentimento, selecione Permitir.

    Caixa de diálogo de consentimento solicitando permissões para o aplicativo

  6. Você deve ver a tabela de dados dos projetos:

    Projeta a grade de dados com colunas e selos classificáveis

Publicando o aplicativo para Power Apps

  1. Depois que o aplicativo estiver pronto para publicação e compartilhamento, verifique se o servidor do Vite foi interrompido usando Ctrl + C e use o seguinte PowerShell:

    npm run build
    pac code push
    
  2. Abra o aplicativo usando o link fornecido para testá-lo!

    App publicado no Power Apps com o link de abertura do aplicativo

Resolução de problemas

Esta seção aborda os problemas comuns que você pode encontrar ao configurar aplicativos de código do Power Apps com Azure SQL Database.

Problemas de Azure SQL Database

Você pode enfrentar esses problemas ao usar bancos de dados Azure SQL.

Não é possível conectar-se ao Azure SQL Database

Sintomas:

  • Erros no tempo limite de conexão
  • Falhas de autenticação ao se conectar com a extensão SQL do VS Code

Soluções:

  1. Verifique as configurações de firewall:

    • No portal do Azure, navegue até o seu SQL Server
    • Vá para SegurançaRede
    • Verifique se "Permitir que os serviços e recursos do Azure possam acessar este servidor" está definido como Sim
    • Adicionar o endereço IP do cliente atual às regras de firewall
  2. Verificar método de autenticação:

    • Verifique se você está usando Microsoft Entra ID - Universal com suporte de MFA no VS Code
    • Verifique se você está conectado à mesma conta de Azure no Azure portal e no VS Code
    • Tente sair e voltar para atualizar os tokens de autenticação
  3. Verifique a conectividade de rede:

    # Test connectivity to SQL Server
    Test-NetConnection -ComputerName "your-sql-server.database.windows.net" -Port 1433
    

Erros de execução de consulta SQL

Sintomas:

  • Erros por permissão negada ao executar scripts SQL
  • Erros Objeto já existente

Soluções:

  1. Problemas de permissão:

    • Verifique se sua conta de usuário está definida como o administrador do Microsoft Entra para o SQL Server
    • Verifique se você tem db_owner ou as permissões apropriadas no banco de dados
  2. Erros de Existência do Objeto:

    • O script SQL inclui DROP instruções – elas são seguras para serem executadas várias vezes
    • Se você receber erros de restrição, execute as instruções de exclusão individualmente primeiro

problemas de Node.js e npm

Você pode enfrentar esses problemas ao usar Node.js e npm.

Porta 3000 já em uso

Sintomas:

  • "EADDRINUSE: endereço já em uso :::3000"
  • O servidor do Vite não inicia

Soluções:

  1. Encerrar o processo existente:

    # Find process using port 3000
    netstat -ano | findstr :3000
    # Kill the process (replace PID with actual process ID)
    taskkill /PID [PID] /F
    
  2. Use a porta alternativa:

    • Para usar uma porta diferente, atualize vite.config.ts
    • Atualizar a biblioteca do cliente Power Apps para a configuração adequada de aplicativos baseados em código

Falhas na instalação do pacote

Sintomas:

  • Erros de instalação do npm
  • Erros não encontrados no módulo

Soluções:

  1. Limpar cache npm:

    npm cache clean --force
    npm install
    
  2. Excluir node_modules e Reinstalar:

    Remove-Item -Recurse -Force node_modules
    Remove-Item package-lock.json
    npm install
    
  3. Problemas de versão do Node.js:

    # Check Node version
    node --version
    # Should be LTS version (18.x or 20.x)
    

Erros de conexão em tempo de execução

Sintomas:

  • "Falha ao carregar dados" no aplicativo React
  • Erros Conexão recusada

Soluções:

  1. Verifique a conexão do Power Platform:

    • Verifique se a conexão SQL Server está funcionando no Power Platform
    • Teste a conexão em Power Apps
  2. Problemas de consentimento:

    • Verifique se você dá consentimento quando o aplicativo é carregado pela primeira vez
    • Limpar o cache do navegador e tentar novamente
  3. Incompatibilidade de ambiente:

    • Verifique se você está executando o aplicativo no mesmo ambiente em que a conexão foi criada
    • Verifique se o perfil do navegador corresponde à sua conta do Power Platform